Re: Marketo Custom Objects & Velocity Scripting

LP_IMS_KJB_7016
Level 2

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

14 REPLIES 14
SanfordWhiteman
Level 10 - Community Moderator

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:

  • You don’t need to maintain counters. $foreach.index is updated automatically.
  • Should use .equals() instead of ==. == has unexpected results in edge cases while .equals() is always predictable.

 

 

LP_IMS_KJB_7016
Level 2

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

SanfordWhiteman
Level 10 - Community Moderator

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.

LP_IMS_KJB_7016
Level 2

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

SanfordWhiteman
Level 10 - Community Moderator

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/"
} )
LP_IMS_KJB_7016
Level 2

Hi @SanfordWhiteman ,

 

thank you for your reply. I have now configured the 1st token, {{my.product-Permalinks}} as advised and shown below:

LP_IMS_KJB_7016_1-1730827506957.png

The 2nd token - {{my.Product-Preferences-v1}} is as shown below:

LP_IMS_KJB_7016_2-1730827572572.png

The email content contains the token reference:

LP_IMS_KJB_7016_3-1730827678739.png

But the preview of the email shows the token reference displayed literally:

LP_IMS_KJB_7016_6-1730827999977.png

Please advise on why I am unable to see the values set as the referenced variable.

 

Regards

 

Karl

 

 

 

 

LP_IMS_KJB_7016
Level 2

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

 

 

Jo_Pitts1
Level 10 - Community Advisor

@LP_IMS_KJB_7016 ,

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

LP_IMS_KJB_7016
Level 2

HI @SanfordWhiteman & @Jo_Pitts1,

 

thank you very much for your replies, I appreciate you taking the time. I believe I have achieved partial success in that I can now reference the values set in the first email script token in the second email script token and use those values to create a HTML block that can then be added dynamically into the email - see below:

 

1st Email script token - {{my.Product-Preference-URLs}} - set as follows:

 

#set ( $productPreferenceURLs = {
	"ProductCode1" : "https://www.webpage1.com/",
	"ProductCode2" : "https://www.webpage2.com/",
	"ProductCode3" : "https://www.webpage3.com/",
	"ProductCode4" : "https://www.webpage4.com/",
	"ProductCode5" : "https://www.webpage5.com/",
} )

 

2nd Email script token - {{my.Fund-Preferences}} - set as follows:

 

## Extract the Product URLs array from the $productPreferenceURLs variable in the {{my.Product-Preference-URLs}} Email Script Token
#set( $referenceURLs = ${productPreferenceURLs} )

## Set a counter to limit the number of products displayed in the email
#set( $counter = 0 )  ## Initialize a counter

#if( $Product_Preference__cList && $Product_Preference__cList.size() > 0 )
  #foreach( $product in $Product_Preference__cList )
      ## Set Product ID and Product Name variables
      #set( $productID = $product.Product__cList.get(0).Product_ID__c )
      #set( $productName = $product.Product__cList.get(0).Name )

      #foreach( $key in $referenceURLs.keySet() )
          #if( $key.equals($productID) )
              #set( $url = ${referenceURLs.get($key)} )
              #break
          #else
              #set( $url = "https://www.webpagehome.com/" )
          #end
      #end
      ## Check if the counter is less than 5
      #if( $counter < 5 )  
          <table width="100%" border="0" cellspacing="0" cellpadding="0"> 
              <tbody> 
                  <tr> 
                      <td align="left" valign="top" style="border-top:solid 2px #d9d9d9; padding: 10px 0 10px 0"> 
                          <table width="100%" border="0" cellspacing="0" cellpadding="0"> 
                              <tbody> 
                                  <tr> 
                                      <td align="left" valign="top" width="57">
                                          <a href="$url?utm_source={{my.UTM-Source}}&utm_medium={{my.UTM-Medium}}&utm_campaign={{my.UTM-Campaign}}" target="_blank">
                                          <img src="http://munchkinID.mktoweb.com/rs/munchkinID/images/icons-pdf-download.gif" width="42" height="40" alt="PDF" style="display:block; border:0; outline:none; text-decoration:none; -ms-interpolation-mode:bicubic;" />
                                          </a>
                                      </td> 
                                      <td align="left" valign="top" class="body-l" style="font-family:Poppins, Arial, sans-serif; font-size:16px; line-height:24px; mso-line-height-rule:exactly; font-weight:700; color:#16293F; text-align:left; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; mso-table-lspace:0pt; mso-table-rspace:0pt; word-break:break-word; hyphens:none; -webkit-hyphens:none; -moz-hyphens:none; padding-top: 2px">
                                          <a href="$url?utm_source={{my.UTM-Source}}&utm_medium={{my.UTM-Medium}}&utm_campaign={{my.UTM-Campaign}}" target="_blank" style="font-weight:700; color:#16293F; text-decoration:none">
                                          $productName
                                          </a>
                                      </td> 
                                  </tr> 
                               </tbody> 
                          </table>
                      </td> 
                  </tr> 
              </tbody> 
          </table>
          ## Increment the counter
          #set( $counter = $counter + 1 )  
      #else
          ## Stop the loop when 5 product preferences have been displayed
          #break  
      #end
  #end	
#else
  #set( $productID = "NUFP" )
  #set( $productName = "No Company Product Preferences" )

  ## Set URL
  #set( $url = "https://www.webpagehome.com/" )
     
  <table width="100%" border="0" cellspacing="0" cellpadding="0"> 
  	<tbody> 
    	<tr> 
        	<td align="left" valign="top" style="border-top:solid 2px #d9d9d9; padding: 10px 0 10px 0"> 
            	<table width="100%" border="0" cellspacing="0" cellpadding="0"> 
                	<tbody> 
                    	<tr> 
                        	<td align="left" valign="top" width="57">
                            	<a href="$url?utm_source={{my.UTM-Source}}&utm_medium={{my.UTM-Medium}}&utm_campaign={{my.UTM-Campaign}}" target="_blank">
                                <img src="http://munchkinID.mktoweb.com/rs/munchkinID/images/icons-pdf-download.gif" width="42" height="40" alt="PDF" style="display:block; border:0; outline:none; text-decoration:none; -ms-interpolation-mode:bicubic;" />
                                </a>
                            </td> 
                            <td align="left" valign="top" class="body-l" style="font-family:Poppins, Arial, sans-serif; font-size:16px; line-height:24px; mso-line-height-rule:exactly; font-weight:700; color:#16293F; text-align:left; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; mso-table-lspace:0pt; mso-table-rspace:0pt; word-break:break-word; hyphens:none; -webkit-hyphens:none; -moz-hyphens:none; padding-top: 2px">
                            	<a href="$url?utm_source={{my.UTM-Source}}&utm_medium={{my.UTM-Medium}}&utm_campaign={{my.UTM-Campaign}}" target="_blank" style="font-weight:700; color:#16293F; text-decoration:none">
                                $productName
                                </a>
                            </td> 
                         </tr> 
                    </tbody> 
                </table>
            </td> 
		</tr> 
    </tbody> 
  </table>		
#end

 

The email references both tokens as follows:

LP_IMS_KJB_7016_0-1731346406132.png

When I Preview or Send a Sample of the email, then the URLs are rendered as expected, e.g. https://www.webpagehome.com/?utm_source={{my.UTM-Source}}&utm_medium={{my.UTM-Medium}}&utm_campaign=...}}

 

However, if I execute the email then the received link is as shown below and when clicked, this resolves to the 2nd URL:

 

http://mkto-lon030380.com/MSA2LUhaVC0zMTcABAGWuzZgyZWx9CrBusdszYVVG-c1X5RiwhE_RG-kFTX70KrWzrivNEP6MW...

 

http://$url/?utm_source={{my.UTM-Source}}&utm_medium={{my.UTM-Medium}}&utm_campaign={{my.UTM-Campaig...

 

As you can see, the literal $url variable is displayed rather than the expected URL as per the Preview and Send Sample tests. Can you explain why this is occurring and what should be done to ensure the URL renders as expected please?

 

Regards

 

SanfordWhiteman
Level 10 - Community Moderator

 You shouldn’t use curly braces/formal references inside directives, like you’re doing here:

 

#set( $referenceURLs = ${productPreferenceURLs} )

 

Formal refs are only necessary inside strings. In other cases they can break parsing, i.e. ${object}.property will not work but $object.property will.

 

In any case, your problem is reusing the same top-level object with different string properties, as opposed to using distinct top level strings. Marketo’s Velocity “uberspector“, which pre-processes URLs to make them trackable, requires distinct variables. You can set the link to not trackable (add class="mktNoTrack") to test the difference.

LP_IMS_KJB_7016
Level 2

Hi @SanfordWhiteman,


thank you for your reply, I'm pleased to report that the suggestion to add class="mktNoTrack" has worked and the URL value is being output in the email now rather than the literal variable.


As it's not ideal to remove tracking for these URLs, I've found one of your blogs - https://blog.teknkl.com/multiple-marketo-tracked-links-in-velocity/amp/ - which outlines a solution to the overcoming the re-use of the same top-level object. Would you recommend this approach still or have you an alternative solution to the issue?


In the meantime, I have a further problem that I wish to overcome in relation to the above requirement. I have 3 further Text Program tokens that are used to set UTM values - {{my.UTM-Campaign}}, {{my.UTM-Source}}, & {{my.UTM-Medium}} - and each token contains a string value, e.g. em_20241113, mkto & email-organic.

 

These tokens are used elsewhere within the email content but I would also like to utilise them in the Email Script token discussed in this thread.

 

How should I reference these tokens within the Email Script token. I am currently hard-coding the values as follows and this method works when I use those variable further into the script to construct the appended UTM string:

## Set UTM values from Program tokens
#set( $utmSource = "marketo" )
#set( $utmMedium = "email-organic" )
#set( $utmCampaign = "em-reports")

 ## Set URL
#set( $uRLFull = "www.webpage.com/" )
#set( $uRLUTM = "?utm_source=${utmSource}&utm_medium=${utmMedium}&utm_campaign=${utmCampaign}" )
#set( $uRLBuild = "${uRLFull}${uRLUTM}" )

<a href="https://${uRLBuild}" target="_blank" style="font-weight:700; color:#16293F; text-decoration:none">

 

I have attempted the following approaches to retrieve the token values from the Text Program tokens but to no avail:

 

## 1st Attempt - Failed
#set( $utmSource = ${my.UTM-Source} )
#set( $utmMedium = ${my.UTM-Medium} )
#set( $utmCampaign = ${my.UTM-Campaign})

## 2nd Attempt - Failed
#set( $utmSource = $my.UTM-Source )
#set( $utmMedium = $my.UTM-Medium )
#set( $utmCampaign = $my.UTM-Campaign)

## 3rd Attempt - Failed
#set( $utmSource = {{my.UTM-Source}} )
#set( $utmMedium = {{my.UTM-Medium}} )
#set( $utmCampaign = {{my.UTM-Campaign}} )

Could you please advise on how I can correctly reference the 3 text Program tokens within the Email Script token?

 

Regards

SanfordWhiteman
Level 10 - Community Moderator
Yes, that approach for multiple tracked links still applies.

Can you please move the new question to a new thread? Thanks.
LP_IMS_KJB_7016
Level 2

Hi @SanfordWhiteman,

 

thank you for confirming and for all your assistance. Thank you also to @Jo_Pitts1 for your feedback.

 

As suggested, I have created a new ticket for how to use Text tokens in a Email Script token - 'Referencing Program Token in Email Scripting Token'.

 

I'm hoping to continue developing the email script token we've discussed in this thread to overcome the looping issue and will post a further update when I have more to report.

 

Regards

SanfordWhiteman
Level 10 - Community Moderator

You need to include both tokens in the email. Also be aware the default= syntax doesn’t work with Velocity tokens.