Good afternoon,
Our Marketo instance is synced to Salesforce which has been configured to retrieve two Custom Salesforce objects, Product Preferences and Company Product. The latter is a parent of the former linked by a Product ID field.
The objects are available in Marketo as filters and triggers and can also be viewed and referenced in a Email Scripting Token to create dynamic content blocks for emails.
The objects however do not contain details relating to their specific website page, the URLs for which are available externally to Salesforce.
These URLs have been imported into a Marketo Custom Object (Product URLs) that is not directly related to a Person record in the set up of the Custom Object.
In terms of relationships, a person can have multiple Product Preferences and each of these Product Preferences, is linked to a record in the Company Product object and in turn, should also have a specific webpage URL available in the Marketo Custom Product URLs object.
I've attempted to loop through the Product Preferences SFDC object in a script, which incidentally has been tested and does work, but have extended the script to then loop through the Product URLs Marketo object (productPermalink) and where the Product ID values achieve a match, pull the URL value into the HTML copy.
#set( $counter = 0 ) ## Initialize a counter
#foreach( $fund in $Product_Preference__cList )
#set( $productID = $fund.Product__cList.get(0).Product_ID__c )
#foreach( $productPermalink in $productPermalink_c )
#if( $productPermalink.productID == $productID )
#if( $counter < 5 ) ## Check if the counter is less than 5
//HTML copy inserted here, e.g. <a href="$productPermalink.permalink" target="_blank">
#set( $counter = $counter + 1 ) ## Increment the counter
#else
#break ## Stop the loop when 5 product preferences have been displayed
#end
#end
#end
#end
However, I cannot get this to work and am wondering whether conceptually this is even possible.
If this is possible in theory, then I think there may be an issue with my object and field references and need to understand how I might retrieve object API names, including the correct __cList suffixes, and script and test the references correctly.
If the approach is flawed however, are there any suggestions of how this might be achieved. It may be a case that it is more efficient to extend the SFDC custom object to include the URL field but I would like to understand whether I could achieve the desired result through Marketo instead.
Any advice would be greatly appreciated.
Regards
Please remember to use the Syntax Highlighter (“Insert/edit code sample”) so your code is readable. I edited your post this time.
These URLs have been imported into a Marketo Custom Object (Product URLs) that is not directly related to a Person record in the set up of the Custom Object.
This won’t work. You can’t access standalone Custom Objects from the Person/Account context.
Depending on how many records there are in this CO, you could instead declare the values in a {{my.token}} (as an typical ArrayList), include that {{my.token}} above your other scripts, and use that as your lookup table.
Also:
$foreach.index
is updated automatically..equals()
instead of ==
. ==
has unexpected results in edge cases while .equals()
is always predictable.
Hi @SanfordWhiteman,
thank you very much for your feedback, much appreciated.
I have attempted to follow your advice but am not able to successfully reference an Email Script token in another Email Script token.
As suggested, I created a new Email Script Token - {{my.Product-URLs}} - in an Email Program which contained a list of products and associated webpage URLs:
{ "ProductCode1 ; https://www.webpage1/, ProductCode2 ; https://www.webpage2/, ProductCode3 ; https://www.webpage3/, ProductCode4 ; https://www.webpage4/, ProductCode5 ; https://www.webpage5/" }
I couldn't however seem able to reference this in a second Email Script Token - {{my.Product-Preferences}}.
So instead, I set a new variable directly in the {{my.Product-Preferences}} token and have successfully retrieved the relevant URL to be inserted into the HTML based on the ProductCodeX value:
#set( $lookupDataString = "ProductCode1 ; https://www.webpage1/, ProductCode2 ; https://www.webpage2/, ProductCode3 ; https://www.webpage3/, ProductCode4 ; https://www.webpage4/, ProductCode5 ; https://www.webpage5/" )
#set( $lookupData = {} )
## Step 1: Strip braces and split
#set( $cleanedData = $lookupDataString.replaceAll("[{}]", "") )
#foreach( $entry in $cleanedData.split(",") )
#set( $pair = $entry.split(";") )
#if( $pair.size() == 2 )
#set( $key = $pair[0].trim().replaceAll('"', '') )
#set( $value = $pair[1].trim().replaceAll('"', '') )
#set( $lookupData = $lookupData.put($key, $value) )
#end
#end
#set( $counter = 0 ) ## Initialize a counter
#foreach( $product in $product_Preference__cList )
#set( $productName = $product.Product__cList.get(0).Name )
#set( $productID = $product.Product__cList.get(0).Product_ID__c )
#foreach( $key in $lookupData.keySet() )
#if( $key.equals($productID) )
#if( $counter < 5 ) ## Check if the counter is less than 5
<a href="${lookupData.get($key)}" target="_blank" style="font-weight:700; color:#16293F; text-decoration:none">
$productName
</a>
#set( $counter = $counter + 1 ) ## Increment the counter
#else
#break ## Stop the loop when 5 product preferences have been displayed
#end
#end
#end
#end
Whilst this approach works, I would prefer that the values set at the top of the script above were managed in a separate token such as {{my.Product-URLs}}. This would allow users to maintain these values and avoid the risk of inadvertent changes elsewhere in the {{my.Product-Preferences}} token.
Could you please advise on whether this is possible and if so, the correct syntax for calling one email script token from another.
In addition, you've highlighted that this approach could be limited if there are a large number of records in the Custom Object. There are 81 currently so I am concerned the volume does make the approach unwieldy. Could there be another way to be able to reference and use CO data in the dynamic creation of an email?
Finally, thanks for the guidance on the counter although it has been included in this instance to limit the number of products displayed in an email and is not directly related to the $foreach loop.
I have also swapped the == references as per your advice.
Regards
As suggested, I created a new Email Script Token - {{my.Product-URLs}} - in an Email Program which contained a list of products and associated webpage URLs:
{ "ProductCode1 ; https://www.webpage1/, ProductCode2 ; https://www.webpage2/, ProductCode3 ; https://www.webpage3/, ProductCode4 ; https://www.webpage4/, ProductCode5 ; https://www.webpage5/" }
I couldn't however seem able to reference this in a second Email Script Token - {{my.Product-Preferences}}.
You don’t reference the token itself. You #set
a value in one token and use it in others.
In addition, you've highlighted that this approach could be limited if there are a large number of records in the Custom Object. There are 81 currently so I am concerned the volume does make the approach unwieldy. Could there be another way to be able to reference and use CO data in the dynamic creation of an email?
The only reason I mentioned the large number is you have a limited number of characters in a script. It’s 50,000 the last time I looked. You’ll be fine for a LONG time.
Hi @SanfordWhiteman,
thanks for your further response. So if I've created an Email Script token titled {{my.Product-Links}} as follows:
#set ( $productLinks = "ProductCode1 ; https://www.webpage1/, ProductCode2 ; https://www.webpage2/, ProductCode3 ; https://www.webpage3/, ProductCode4 ; https://www.webpage4/, ProductCode5 ; https://www.webpage5/" )
How should I use the value in the second Email script token titled {{my.Product-Preferences}}? I've attempted it as follows but am not receiving the expected results:
#set( $lookupData = {} )
#set( $cleanedData = $productLinks.replaceAll("[{}]", "") )
#foreach( $entry in $cleanedData.split(",") )
#set( $pair = $entry.split(";") )
#if( $pair.size() == 2 )
#set( $key = $pair[0].trim().replaceAll('"', '') )
#set( $value = $pair[1].trim().replaceAll('"', '') )
#set( $lookupData = $lookupData.put($key, $value) )
#end
#end
Regards
You don’t use any kind of non-standard encoding. Or any encoding at all. Just set an object literal.
#set ( $productLinks = {
"ProductCode1" : "https://www.webpage1/",
"ProductCode2" : "https://www.webpage2/",
"ProductCode3" : "https://www.webpage3/"
} )
Hi @SanfordWhiteman ,
thank you for your reply. I have now configured the 1st token, {{my.product-Permalinks}} as advised and shown below:
The 2nd token - {{my.Product-Preferences-v1}} is as shown below:
The email content contains the token reference:
But the preview of the email shows the token reference displayed literally:
Please advise on why I am unable to see the values set as the referenced variable.
Regards
Karl
Hi @SanfordWhiteman ,
apologies for following up but I was wondering if you'd had the chance to review my response below. If you can advise on how to correctly reference the $productPermalinks variable that was set in the {{my.product-Permalinks}} token in the 2nd token titled {{my.Product-Preferences-v1}}.
Being able to maintain a list of URLs in the {{my.product-Permalinks}} token that can be referenced from {{my.Product-Preferences-v1}} will be an acceptable solution for the requirement I'm attempting to solve so it would be great if you're able to advise or confirm the correct method for achieving that please.
Regards
You need to include both tokens in the email. Also be aware the default=
syntax doesn’t work with Velocity tokens.
the key thing to understand here is that variables are not scoped within a token.
if you set a variable in one token, you can reference it in a subsequent token.
so, this is perfectly valid:
my.setupOutput
#set($myOutput = "This is some output")
#set($myOtherOutput = "This is some more output")
#set($myFinalOutput = "$myOutout$ - ${myOtherOutput}")
my.displayOutput
${myFinalOutput}
And then in your email you put {{my.setupOutput}} at the top of the email, and then you can use {{my.displayOutput}} as often as you want after that without needing {{my.setupOutput}} over and over again in the email.
There are caveats around this to do with looping, but we'll leave that for another day.
Cheers
Jo