/**
* @name Create Google Ads Expanded Text Ad
*
* @overview The script creates an expanded text ad in the given campaign,
* adgroup with the specified elements.
* for more details.
*
* @author Roland Bende []
*
* @version 1.0.2
*
* @changelog
* - version 1.0.2
* - Added new functions: My Ad Customizer, Customize Expanded Text Ads with product data
* - version 1.0.1
* - Expension of description legal characters list.
* - version 1.0.0
* - Released initial version.
*/
// OPTIONS
/**
* Define the campaign id where the adgroup present.
*
* @var {string} CAMPAIGN_ID Campaign id
*/
var CAMPAIGN_ID = '1733650936'; //
/**
* Define the Adgroup name.
*
* @var {string} ADGROUP_NAME Adgroup name.
*/
var ADGROUP_NAME = 'Test AdGroup';
/**
* Define Expanded text ad templates
*
* @var {array <Object>} EXPANDED_TEXT_ADS Expanded text ads templates containg objects(Keys eg.: Headline 1, Desc 2., etc...)
*/
var EXPANDED_TEXT_AD_TEMPLATES = [
{
'ad_template_id': '1',
'headline1': '{{=product_name}}', // max. length: 30
'headline2': '{{=product_category}} ingyen szállítással', // max. length: 30
'headline3': 'Azonnal | Raktárról', // max. length: 30
'desc1': 'Profi {{=product_category}} a szakértőtől. Részletes termékspecifikáció, hogy a megfelelőt választhasd.', // max. length: 90
'desc2': 'Magyarországi márkaszerviz hálózattal, gyári garanciával.', // max. length: 90
'path1': '{{=product_url_path1}}', // max. length: 15
'path2': '{{=product_url_path2}}', // max. length: 15
'finalurl': '{{=product_url_final}}'
},
{
'ad_template_id': '2',
'headline1': '{{=product_name}}', // max. length: 30
'headline2': 'Már egymásra találtatok?', // max. length: 30
'headline3': 'Csak nem tudod, hol vedd meg?', // max. length: 30
'desc1': 'Vedd meg tőlünk! Most akár 4 órán belül nálad lehet a saját {{=product_name}}.', // max. length: 90
'desc2': 'Magyarországi márkaszerviz hálózattal, gyári garanciával.', // max. length: 90
'path1': '{{=product_url_path1}}', // max. length: 15
'path2': '{{=product_url_path2}}', // max. length: 15
'finalurl': '{{=product_url_final}}'
}
];
/**
* Define products
*
* @var {array <Object>}
*/
var PRODUCTS = [
{
'name': 'ASUS ROG Zephyrus GM501',
'category': 'Notebook',
'url_path1': 'notebook',
'url_path2': 'asus',
},
{
'name': 'Asus ZenBook Flip S UX370',
'category': 'Notebook',
'url_path1': 'notebook',
'url_path2': 'asus',
},
{
'name': 'HP Spectre x360 13',
'category': 'Notebook',
'url_path1': 'notebook',
'url_path2': 'hp',
}
];
// FUNCTIONS
function main() {
Logger.log('Script START!');
createExpandedTextAdsFromProductData(CAMPAIGN_ID, ADGROUP_NAME, PRODUCTS, EXPANDED_TEXT_AD_TEMPLATES);
Logger.log('Script END!');
}
/**
* Create Expanded Text Ads From Product Data
*
* Dependencies: getGoogleAdsAdGroupByNameAndCampaignId(), customizeExpandedTextAdsWithProductData(), createGoogleAdsExtendedTextAd(), setGoogleAdsScriptTimeout()
*
* @param {string} campaign_id
* @param {string} adgroup_name
* @param {array <Object>} prodcuts
* @param {array <Object>} expanded_text_ad_templates
*
* @return void
*/
function createExpandedTextAdsFromProductData(campaign_id, adgroup_name, products, expanded_text_ad_templates) {
var adGroup = getGoogleAdsAdGroupByNameAndCampaignId(adgroup_name, campaign_id);
var expandedTextAdTemplates = expanded_text_ad_templates;
for(var i=0; i < products.length; i++) {
var productAdCopies = [];
var product = products[i];
productAdCopies = customizeExpandedTextAdsWithProductData(product, expandedTextAdTemplates);
productAdCopies.forEach(function(element){
var ad = createGoogleAdsExtendedTextAd(adGroup, element);
if(ad !== null) {
Logger.log('Ad id: ' + ad.getId());
Logger.log('---');
Logger.log(ad.getHeadlinePart1() + ' | ' + ad.getHeadlinePart2() + ' | ' + ad.getHeadlinePart3());
Logger.log(ad.getDescription1());
Logger.log(ad.getDescription2());
Logger.log(ad.getPath1() + '/' + ad.getPath2());
Logger.log(ad.urls().getFinalUrl());
Logger.log('---');
}
setGoogleAdsScriptTimeout(0.2);
});
}
return;
}
/**
* Customize Expanded Text Ads with product data
*
* Dependencies: myAdCustomizer()
*
* @param {object} product_data
* @param {array <Object>} expanded_text_ad_templates
*
* @return {array <Object>} customizedAdTemplates
*/
function customizeExpandedTextAdsWithProductData(product_data, expanded_text_ad_templates) {
var customizedAdTemplates = [];
var productData = product_data;
var adTemplates = expanded_text_ad_templates;
var adTemplatesLength = adTemplates.length;
for(var index=0; index < adTemplatesLength; index++) {
var adTemplate = adTemplates[index];
var customizedAdTemplate = myAdCustomizer(adTemplate, '{{=product_name}}', productData['name']);
customizedAdTemplate = myAdCustomizer(customizedAdTemplate, '{{=product_category}}', productData['category']);
customizedAdTemplate = myAdCustomizer(customizedAdTemplate, '{{=product_url_path1}}', productData['url_path1']);
customizedAdTemplate = myAdCustomizer(customizedAdTemplate, '{{=product_url_path2}}', productData['url_path2']);
customizedAdTemplate = myAdCustomizer(customizedAdTemplate, '{{=product_url_final}}', productData['url_final']);
customizedAdTemplates.push(customizedAdTemplate);
}
return customizedAdTemplates;
}
/**
* My Ad Customizer - Replaces given variables with the given values in the given Ad object.
*
* Dependecies: stringReplace()
*
* @param {object <String>} ad_elements
* @param {string} my_ad_customizer_variable
* @param {string} my_ad_customizer_value
*
* @return {object <String>} adElements
*/
function myAdCustomizer(ad_elements, my_ad_customizer_variable, my_ad_customizer_value) {
var adElements = ad_elements;
var newAdElements = {};
for(var key in adElements) {
if(adElements.hasOwnProperty(key)) {
newAdElements[key] = stringReplace(adElements[key], my_ad_customizer_variable, my_ad_customizer_value);
}
}
return newAdElements;
}
/**
* Replace string part in string with the given string using regular expression.
*
* Dependencies: isVariableNull(), isVariableString(), isStringEmpty()
*
* @param {string} my_string The string to operate on.
* @param {string} replace_what The string part which need to be replaced.
* @param {string} replace_to The new string part which
*
* @return {string}
*/
function stringReplace(my_string, replace_what, replace_to) {
if(isVariableNull(my_string) === false && isVariableString(my_string) === true && isStringEmpty(my_string) === false) {
var my_regex = new RegExp(replace_what, 'g');
return my_string.replace(my_regex, replace_to);
} else {
return my_string;
}
}
/**
* Check variable is string type variable.
*
* @param {string} my_var The variable to check.
*
* @return {boolean}
*/
function isVariableString(my_var) {
if(typeof my_var === "string") {
return true;
} else {
Logger.log('Error: Given param ('+ my_var +') is not a string!');
return false;
}
}
/**
* Check string is empty or not.
*
* @param {string} my_string The string to check.
*
* @return {boolean}
*/
function isStringEmpty(my_string) {
if(isVariableString(my_string) === false) {
return false;
}
return my_string.length === 0 ? true : false;
}
/**
* Check variable is empty or not.
*
* @param {string} my_var The variable to check.
*
* @return {boolean}
*/
function isVariableNull(my_var) {
return my_var === null ? true : false;
}
/**
* Get Google Ads AdGroup by name and it's Campaign id.
*
*
* @param {string} my_adgroup_name AdGroup name selector.
* @param {number} my_camapign_id Campaign id selector. Basically Not neccessary but recommended because of permormance reasons.
*
* @return {?AdGroup} my_selected_adgroup Returns selected AdGroup. If error occured it will be null.
*/
function getGoogleAdsAdGroupByNameAndCampaignId(my_adgroup_name, my_campaign_id) {
var my_selected_adgroup = null;
try {
my_selected_adgroup = AdsApp.adGroups()
.withCondition('Name = "'+ my_adgroup_name +'"')
.withCondition('CampaignId="'+ my_campaign_id +'"')
.get()
.next();
} catch(e) {
Logger.log('Warning: No AdGroup found with the name ' + my_adgroup_name + ' in given campaign(id:'+ my_campaign_id +')!');
}
return my_selected_adgroup;
}
/**
* Create Google Ads extended text ad.
*
*
* @param {!AdGroup} my_adgroup Destination AdGroup entity.
* @param {object} my_expanded_text_ad_settings
*
* @return {!ExpandedTextAd || null} Normally returns a valid Expanded Text Ad entity. If error occured it returns null as value!
*/
function createGoogleAdsExtendedTextAd(my_adgroup, my_expanded_text_ad_settings) {
var ad = null;
var adGroup = my_adgroup;
var adSettings = my_expanded_text_ad_settings;
var adHeadline1 = createGoogleAdsExtendedTextAdHeadlineTextFromString(adSettings['headline1']);
var adHeadline2 = createGoogleAdsExtendedTextAdHeadlineTextFromString(adSettings['headline2']);
var adHeadline3 = createGoogleAdsExtendedTextAdHeadlineTextFromString(adSettings['headline3']);
var adDesc1 = createGoogleAdsExtendedTextAdDescriptionTextFromString(adSettings['desc1']);
var adDesc2 = createGoogleAdsExtendedTextAdDescriptionTextFromString(adSettings['desc2']);
var adPath1 = createGoogleAdsExtendedTextAdPathTextFromString(adSettings['path1']);
var adPath2 = createGoogleAdsExtendedTextAdPathTextFromString(adSettings['path2']);
var adFinalUrl = createGoogleAdsExtendedTextAdFinalUrlTextFromString(adSettings['finalurl']);
if(!adHeadline1 || !adHeadline2 || !adDesc1 || !adFinalUrl) {
Logger.log("Error: There was an error when tried to create Expanded Text Ad!");
Logger.log("Required parameter(s) missing!");
return null;
}
try {
var adOperation = adGroup.newAd().expandedTextAdBuilder()
.withHeadlinePart1(adHeadline1)
.withHeadlinePart2(adHeadline2)
.withHeadlinePart3(adHeadline3)
.withDescription1(adDesc1)
.withDescription2(adDesc2)
.withPath1(adPath1)
.withPath2(adPath2)
.withFinalUrl(adFinalUrl)
.build();
ad = adOperation.getResult();
} catch(e) {
Logger.log('Error: There was an error when tried to create Expanded Text Ad!');
Logger.log(e);
}
return ad;
}
/**
* Create Google Ads Expanded Text Ad Headline from given string.
*
* Dependecies: isStringlongerThen(), sanitizeGoogleAdsExpandedTextAdHeadlineText()
*
*
* @param {string} my_headline The headline string.
*
* @return {string || null} Normally returns a valid Expanded Text Ad Headline. If error occured it returns null as value!
*/
function createGoogleAdsExtendedTextAdHeadlineTextFromString(my_headline) {
var sanitized_headline_text = sanitizeGoogleAdsExpandedTextAdHeadlineText(my_headline);
var expanded_text_ad_headline_max_char_limit = 30;
if(isStringlongerThen(sanitized_headline_text, expanded_text_ad_headline_max_char_limit)) {
Logger.log("Error: Can't create AdCopy Headline! Given string ("+ sanitized_headline_text +") is longer then "+expanded_text_ad_headline_max_char_limit+" chars!");
return null;
}
return sanitized_headline_text;
}
/**
* Create Google Ads Expanded Text Ad Description from given string.
*
* Dependecies: isStringlongerThen(), sanitizeGoogleAdsExpandedTextAdDescriptionText()
*
*
* @param {string} my_desc The description string.
*
* @return {string || null} Normally returns a valid Expanded Text Ad Description. If error occured it returns null as value!
*/
function createGoogleAdsExtendedTextAdDescriptionTextFromString(my_desc) {
var sanitized_description_text = sanitizeGoogleAdsExpandedTextAdDescriptionText(my_desc); // ToDo Desc. sanitize function
var expanded_text_ad_description_max_char_limit = 90;
if(isStringlongerThen(sanitized_description_text, expanded_text_ad_description_max_char_limit)) {
Logger.log("Error: Can't create AdCopy Description! Given string ("+ sanitized_description_text +") is longer then "+expanded_text_ad_description_max_char_limit+" chars!");
return null;
}
return sanitized_description_text;
}
/**
* Create Google Ads Expanded Text Ad Path from given string.
*
* Dependecies: isStringlongerThen(), sanitizeGoogleAdsExpandedTextAdPathText()
*
*
* @param {string} my_path The path string.
*
* @return {string || null} Normally returns a valid Expanded Text Ad Path. If error occured it returns null as value!
*/
function createGoogleAdsExtendedTextAdPathTextFromString(my_path) {
var sanitized_path_text = sanitizeGoogleAdsExpandedTextAdPathText(my_path);
var expanded_text_ad_path_max_char_limit = 15;
if(isStringlongerThen(sanitized_path_text, expanded_text_ad_path_max_char_limit)) {
Logger.log("Error: Can't create AdCopy Path! Given string ("+ sanitized_path_text +") is longer then "+expanded_text_ad_path_max_char_limit+" chars!");
return null;
}
return sanitized_path_text;
}
/**
* Create Google Ads Expanded Text Ad Final URL from given string.
*
* Dependecies: isStringlongerThen(), sanitizeGoogleAdsExpandedTextAdFinalUrlText()
*
*
* @param {string} my_final_url The final url string.
*
* @return {string || null} Normally returns a valid Expanded Text Final Url. If error occured it returns null as value!
*/
function createGoogleAdsExtendedTextAdFinalUrlTextFromString(my_final_url) {
var sanitized_path_text = sanitizeGoogleAdsExpandedTextAdFinalUrlText(my_final_url);
return sanitized_path_text;
}
/**
* Remove illegal characters from given Google Ads Expanded Text Ad Headline text.
*
* @param {string} my_headline_text The headline string to sanitize.
*
* @return {string} sanitized_text Sanitized headline string. Illegal chars are removed!
*/
function sanitizeGoogleAdsExpandedTextAdHeadlineText(my_headline_text) {
var sanitized_text = my_headline_text.replace(/[^0-9a-záéíóöőüűú+'"_-]/gi, " ");
sanitized_text = sanitized_text.replace(/ +/g, " ");
sanitized_text = sanitized_text.trim();
return sanitized_text;
}
/**
* Remove illegal characters from given Google Ads Expanded Text Ad Description text.
*
* @param {string} my_desc_text The description string to sanitize.
*
* @return {string} sanitized_text Sanitized description string. Illegal chars are removed!
*/
function sanitizeGoogleAdsExpandedTextAdDescriptionText(my_desc_text) {
var sanitized_text = my_desc_text.replace(/[^0-9a-záéíóöőüűú+'".,!?()[]_-]/gi, " ");
sanitized_text = sanitized_text.replace(/ +/g, " ");
sanitized_text = sanitized_text.trim();
return sanitized_text;
}
/**
* Remove illegal characters from given Google Ads Expanded Text Ad Path.
*
* @param {string} my_path_text The path string to sanitize.
*
* @return {string} sanitized_text Sanitized path string. Illegal chars are removed!
*/
function sanitizeGoogleAdsExpandedTextAdPathText(my_path_text) {
var sanitized_text = my_path_text.toLowerCase(); // Only lowercase letters
sanitized_text = sanitized_text.replace(/[^0-9a-záéíóöőüűú_-]/g, " ");
sanitized_text = sanitized_text.replace(/ +/g, " ");
sanitized_text = sanitized_text.trim();
return sanitized_text;
}
/**
* Remove illegal characters from given Google Ads Expanded Text Ad Final Url.
*
*
* @param {string} my_final_url_text The final url string to sanitize.
*
* @return {string} sanitized_text Sanitized path string. Illegal chars are removed!
*/
function sanitizeGoogleAdsExpandedTextAdFinalUrlText(my_final_url_text) {
var sanitized_text = my_final_url_text.toLowerCase();
sanitized_text = sanitized_text.trim();
return sanitized_text;
}
/**
* Check string lenght is it is longer than the given limit.
*
*
* @param {string} my_string The string to check.
* @param {number} my_limit The maximum length of the string.
*
* @return {boolean} If incorrect param type was given then it return false with an error log.
*/
function isStringlongerThen(my_string, my_limit) {
if(isVariabelString(my_string) === false) {
return false;
}
if(isVariabelNumber(my_limit) === false) {
return false;
}
if(my_string.length > my_limit) {
return true;
}
return false;
}
/**
* Check variable is string type variable.
*
* @param {string} my_var The variable to check.
*
* @return {boolean}
*/
function isVariabelString(my_var) {
if(typeof my_var === "string") {
return true;
} else {
Logger.log('Error: Given param ('+ my_var +') is not a string!');
return false;
}
}
/**
* Check variable is number type.
*
* @param {string} my_var The variable to check.
*
* @return {boolean}
*/
function isVariabelNumber(my_var) {
if(typeof my_var === "number") {
return true;
} else {
Logger.log('Error: Given param ('+ my_var +') is not a number!');
return false;
}
}
/**
* Pretty print javascript object as a string for debug purpose.
*
* @param {object} value The javascript array to pretty print.
*
* @return {string} Human-readable object.
*/
function prettyPrintObject(value) {
return JSON.stringify(value, null, '\t');
}
/**
*
* Set timeout for Google Ads Script
*
*
* @param {integer} Timeout multiplier.
*
*/
function setGoogleAdsScriptTimeout(multiplier) {
var timeout_multiplier = multiplier;
Utilities.sleep(timeout_multiplier * 3 * 1000);
}