Working with Salesforce Multi-Select Picklists in AMPscript

Custom Multi-Select Picklists in Sales/Service Cloud allow users to select one or more values from a predefined list:

When a user picks more than one value, the selected values show in a field separated by a semicolons:

The values will be in the same, semicolon-delimited format, if you synchronize the picklist field into Marketing Cloud and store the data in a Data Extension. This means that you will have to break each of those fields up into separate values to be able to use them in your script.

My example multi-select picklist in Sales Cloud is used for storing subscriber preferences and has five possible values:

  • Events
  • Newsletters
  • Promotions
  • Special Offers
  • Surveys

In this tutorial, we will first pull the multi-select picklist data onto a CloudPage to display it for the subscriber as an HTML form, where they can pick which of the above they are interested in, and once they submit the form, we will write that data back into Sales Cloud.

Splitting a string by a delimiter

First, let’s pull the data into our script. In the example below, I will use the RetrieveSalesforceObjects() function to pull the data onto a CloudPage directly from Sales/Service Cloud. Depending on your use case, you might want to use the Lookup() or LookupRows() functions instead, if you are working with Synchronized Data Extensions.

My multi-select picklist field is called Preferences__c and it’s on the Contact object:

%%[
set @subscriberKey = AttributeValue(_subscriberKey)
set @subscriberrows = retrievesalesforceobjects(
"contact",
"firstname,lastname,email,preferences__c",
"id", "=", @subscriberKey)
if rowcount(@subscriberrows) == 1 then
set @subscriberrow = row(@subscriberrows, 1)
set @firstname = field(@subscriberrow, "firstname")
set @lastname = field(@subscriberrow, "lastname")
set @email = field(@subscriberrow, "email")
set @preferences__c = field(@subscriberrow, "preferences__c")
endif
]%%
%%=v(@preferences__c)=%%

When you output the data using %%=v(@preferences__c)=%%, you will see it in exactly the same semicolon-delimited format as mentioned earlier:

In order to split multi-select picklist data into separate values and to be able to assign those values to AMPscript variables, we will use the BuildRowSetFromString() function. The BuildRowSetFromString function will create a rowset from a character string by splitting the string at the specified delimiter – in our case, a semicolon.

As a first step, we will check if our @preferences__c variable has any data inside by using the Empty() function. If the variable is not empty, we can proceed with the BuildRowSetFromString function:

%%[
set @subscriberKey = AttributeValue(_subscriberKey)
set @subscriberrows = retrievesalesforceobjects(
"contact",
"firstname,lastname,email,preferences__c",
"id", "=", @subscriberKey)
if rowcount(@subscriberrows) == 1 then
set @subscriberrow = row(@subscriberrows, 1)
set @firstname = field(@subscriberrow, "firstname")
set @lastname = field(@subscriberrow, "lastname")
set @email = field(@subscriberrow, "email")
set @preferences__c = field(@subscriberrow, "preferences__c")
endif
if not empty(@Preferences__c) then
set @rs = buildrowsetfromstring(@preferences__c,';')
Output(rowcount(@rs))
endif
]%%

Output(rowcount(@rs)) will output the number of values contained in our multi-select picklist field.

Now let’s add a loop to iterate through the rowset and match the values in our script with multi-select picklist values from Saleforce. Remember, that the more picklist values you have in Salesforce, the more complicated your loop will get.

The biggest challenge we need to tackle in our script, is the fact that we never know how many and which values each subscriber will have assigned to them. That’s why we need to iterate through all of the values and use a conditional statement to check if each of the values found matches a picklist value we know exists in Salesforce.

Here’s how the script will look like once we add our loop with the conditional statements:

%%[
set @subscriberKey = AttributeValue(_subscriberKey)
set @subscriberRows = RetrieveSalesforceObjects(
"Contact",
"FirstName,LastName,Email,Preferences__c",
"Id", "=", @subscriberKey )
if RowCount(@subscriberRows) == 1 then /* there should only be one row */
var @subscriberRow, @firstName, @lastName, @email
set @subscriberRow = Row(@subscriberRows, 1)
set @firstName = Field(@subscriberRow, "FirstName")
set @lastName = Field(@subscriberRow, "LastName")
set @email = Field(@subscriberRow, "Email")
set @Preferences__c = Field(@subscriberRow, "Preferences__c")
IF NOT EMPTY(@Preferences__c) THEN
SET @rs = BuildRowsetFromString(@Preferences__c,';')
IF rowcount(@rs) > 0 THEN
FOR @i=1 TO rowcount(@rs) DO
SET @val = Field(Row(@rs,@i),1)
IF @val == "Surveys" THEN
SET @Surveys = true
ELSEIF @val == "Events" THEN
SET @Events = true
ELSEIF @val == "Newsletters" THEN
SET @Newsletters = true
ELSEIF @val == "Promotions" THEN
SET @Promotions = true
ELSEIF @val == "Special Offers" THEN
SET @Offers = true
ENDIF
NEXT @i
ELSE
SET @Newsletters = ""
SET @Events = ""
SET @Offers = ""
SET @Survays = ""
SET @Promotions = ""
ENDIF
ENDIF
endif
]%%
@Surveys: %%=v(@Surveys)=%%<br>
@Events: %%=v(@Events)=%%<br>
@Newsletters: %%=v(@Newsletters)=%%<br>
@Promotionss: %%=v(@Promotions)=%%<br>
@Offers: %%=v(@Offers)=%%<br>

Above script will display true for all values where it found a match.

Let’s now add an HTML form and display our picklist data as checkboxes.

HTML checkboxes and AMPscript

We will use AMPscript and the values retrieved using the BuildRowSetFromString function to conditionally mark checkboxes as checked if there is a matching value in Salesforce. In HTML forms, the checked attribute specifies that an element should be pre-selected when the page loads (for type=”checkbox” or type=”radio”):

<input type="checkbox" checked>

For each of the checkboxes representing the multi-select picklist values, we will add an AMPscript variable to conditionally add the checked attribute when the value is found in our rowset. Let’s also add the basic subscriber information like First Name, Last Name and Email to the form:

<h2>Please fill in the form:</h2>
<form action="%%=RequestParameter('PAGEURL')=%%" method="post">
<label>First name: </label><input type="text" name="firstname" required="" value="%%=v(@firstName)=%%"><br>
<label>Last name: </label><input type="text" name="lastname" required="" value="%%=v(@lastName)=%%"><br>
<label>Email: </label><input type="text" name="email" required="" value="%%=v(@email)=%%"><br><br>
<h2>Update your subscriptions:</h2>
<input name="newsletters" type="checkbox" %%=v(@Newsletters)=%%><label>Newsletters</label><br>
<input name="events" type="checkbox" %%=v(@Events)=%%><label>Events</label><br>
<input name="offers" type="checkbox" %%=v(@Offers)=%%><label>Special Offers</label><br>
<input name="surveys" type="checkbox" %%=v(@Surveys)=%%><label>Surveys</label><br>
<input name="promotions" type="checkbox" %%=v(@Promotions)=%%><label>Promotions</label><br>
<input name="submitted" type="hidden" value="true"><br>
<input type="submit" value="Submit">
</form>

Now we need to adjust or script to display the word checked instead of true in case there is a match:

%%[
set @subscriberKey = AttributeValue(_subscriberKey)
set @subscriberRows = RetrieveSalesforceObjects(
"Contact",
"FirstName,LastName,Email,Preferences__c",
"Id", "=", @subscriberKey )
if RowCount(@subscriberRows) == 1 then /* there should only be one row */
var @subscriberRow, @firstName, @lastName, @email
set @subscriberRow = Row(@subscriberRows, 1)
set @firstName = Field(@subscriberRow, "FirstName")
set @lastName = Field(@subscriberRow, "LastName")
set @email = Field(@subscriberRow, "Email")
set @Preferences__c = Field(@subscriberRow, "Preferences__c")
IF NOT EMPTY(@Preferences__c) THEN
SET @rs = BuildRowsetFromString(@Preferences__c,';')
IF rowcount(@rs) > 0 THEN
FOR @i=1 TO rowcount(@rs) DO
SET @val = Field(Row(@rs,@i),1)
IF @val == "Surveys" THEN
SET @Surveys = "checked"
ELSEIF @val == "Events" THEN
SET @Events = "checked"
ELSEIF @val == "Newsletters" THEN
SET @Newsletters = "checked"
ELSEIF @val == "Promotions" THEN
SET @Promotions = "checked"
ELSEIF @val == "Special Offers" THEN
SET @Offers = "checked"
ENDIF
NEXT @i
ELSE
SET @Newsletters = ""
SET @Events = ""
SET @Offers = ""
SET @Survays = ""
SET @Promotions = ""
ENDIF
ENDIF
endif
]%%
<h2>Please fill in the form:</h2>
<form action="%%=RequestParameter('PAGEURL')=%%" method="post">
<label>First name: </label><input type="text" name="firstname" required="" value="%%=v(@firstName)=%%"><br>
<label>Last name: </label><input type="text" name="lastname" required="" value="%%=v(@lastName)=%%"><br>
<label>Email: </label><input type="text" name="email" required="" value="%%=v(@email)=%%"><br><br>
<h2>Update your subscriptions:</h2>
<input name="newsletters" type="checkbox" %%=v(@Newsletters)=%%><label>Newsletters</label><br>
<input name="events" type="checkbox" %%=v(@Events)=%%><label>Events</label><br>
<input name="offers" type="checkbox" %%=v(@Offers)=%%><label>Special Offers</label><br>
<input name="surveys" type="checkbox" %%=v(@Surveys)=%%><label>Surveys</label><br>
<input name="promotions" type="checkbox" %%=v(@Promotions)=%%><label>Promotions</label><br>
<input name="submitted" type="hidden" value="true"><br>
<input type="submit" value="Submit">
</form>

Now you should be able to correctly display the multi-select picklist data for each subscriber visiting your CloudPage.

Update Multi-Select Picklist values in Salesforce using AMPscript

Once the subscriber makes changes to their preferences and clicks on the Submit button, the page will reload and the form parameters will be posted back to the same page. If you would like to learn more about this approach of working with forms on CloudPages, take a look at one of my earlier articles: Create a Sales Cloud-integrated lead capture form using AMPscript.

Now we can add the script to process the posted form data and update it in Salesforce:

SET @preferences = CONCAT(
Iif(RequestParameter("newsletters") == "on", "Newsletters;", ""),
Iif(RequestParameter("events") == "on", "Events;", ""),
Iif(RequestParameter("offers") == "on", "Special Offers;", ""),
Iif(RequestParameter("surveys") == "on", "Surveys;", ""),
Iif(RequestParameter("promotions") == "on", "Promotions", ""),
)
if not Empty(@preferences) then
SET @updateRecord = UpdateSingleSalesforceObject(
"Contact", RequestParameter("subkey"),
"FirstName", RequestParameter("firstname"),
"LastName", RequestParameter("lastname"),
"Email", RequestParameter("email"),
"Preferences__c", @preferences)
else
SET @updateRecord = UpdateSingleSalesforceObject(
"Contact", RequestParameter("subkey"),
"FirstName", RequestParameter("firstname"),
"LastName", RequestParameter("lastname"),
"Email", RequestParameter("email"),
"fieldsToNull", "Preferences__c")
endif

To pass the data back to Salesforce, we need to transform the posted form data back into the initial form: a string with semicolon-delimited values. In order to achieve this, I have used the Iif() function to conditionally check which values have been selected in the form (a selected checkbox will return the value of on). If a parameter returns the on value, we substitute it with the corresponding picklist value and concatenate all the returned values together into one string to pass them to Salesforce.

The full script

Here is the full script, including a try/catch statement for debugging:

<script runat="server">
Platform.Load("Core","1.1.1");
try{
</script>
%%[
IF RequestParameter("submitted") == true THEN
SET @preferences = CONCAT(
Iif(RequestParameter("newsletters") == "on", "Newsletters;", ""),
Iif(RequestParameter("events") == "on", "Events;", ""),
Iif(RequestParameter("offers") == "on", "Special Offers;", ""),
Iif(RequestParameter("surveys") == "on", "Surveys;", ""),
Iif(RequestParameter("promotions") == "on", "Promotions", ""),
)
if not Empty(@preferences) then
SET @updateRecord = UpdateSingleSalesforceObject(
"Contact", RequestParameter("subkey"),
"FirstName", RequestParameter("firstname"),
"LastName", RequestParameter("lastname"),
"Email", RequestParameter("email"),
"Preferences__c", @preferences)
else
SET @updateRecord = UpdateSingleSalesforceObject(
"Contact", RequestParameter("subkey"),
"FirstName", RequestParameter("firstname"),
"LastName", RequestParameter("lastname"),
"Email", RequestParameter("email"),
"fieldsToNull", "Preferences__c")
endif
]%%
Your preferences have been updated.
%%[ELSE
set @subscriberKey = AttributeValue(_subscriberKey)
set @subscriberRows = RetrieveSalesforceObjects(
"Contact",
"FirstName,LastName,Email,Preferences__c",
"Id", "=", @subscriberKey)
if RowCount(@subscriberRows) == 1 then
var @subscriberRow, @firstName, @lastName, @email
set @subscriberRow = Row(@subscriberRows, 1)
set @firstName = Field(@subscriberRow, "FirstName")
set @lastName = Field(@subscriberRow, "LastName")
set @email = Field(@subscriberRow, "Email")
set @Preferences__c = Field(@subscriberRow, "Preferences__c")
IF NOT EMPTY(@Preferences__c) THEN
SET @rs = BuildRowsetFromString(@Preferences__c,';')
IF rowcount(@rs) > 0 THEN
FOR @i=1 TO rowcount(@rs) DO
SET @val = Field(Row(@rs,@i),1)
IF @val == "Surveys" THEN
SET @Surveys = "checked"
ELSEIF @val == "Events" THEN
SET @Events = "checked"
ELSEIF @val == "Newsletters" THEN
SET @Newsletters = "checked"
ELSEIF @val == "Promotions" THEN
SET @Promotions = "checked"
ELSEIF @val == "Special Offers" THEN
SET @Offers = "checked"
ENDIF
NEXT @i
ELSE
SET @Newsletters = ""
SET @Events = ""
SET @Offers = ""
SET @Survays = ""
SET @Promotions = ""
ENDIF
ENDIF
endif
]%%
<h2>Please fill in the form:</h2>
<form action="%%=RequestParameter('PAGEURL')=%%" method="post">
<label>First name: </label><input type="text" name="firstname" required="" value="%%=v(@firstName)=%%"><br>
<label>Last name: </label><input type="text" name="lastname" required="" value="%%=v(@lastName)=%%"><br>
<label>Email: </label><input type="text" name="email" required="" value="%%=v(@email)=%%"><br><br>
Pref: %%=v(@Preferences__c)=%%<br><br>
<h2>Update your subscriptions:</h2>
<input name="newsletters" type="checkbox" %%=v(@Newsletters)=%%><label>Newsletters</label><br>
<input name="events" type="checkbox" %%=v(@Events)=%%><label>Events</label><br>
<input name="offers" type="checkbox" %%=v(@Offers)=%%><label>Special Offers</label><br>
<input name="surveys" type="checkbox" %%=v(@Surveys)=%%><label>Surveys</label><br>
<input name="promotions" type="checkbox" %%=v(@Promotions)=%%><label>Promotions</label><br>
<input name="subkey" type="hidden" value="%%=v(@subscriberKey)=%%"><br>
<input name="submitted" type="hidden" value="true"><br>
<input type="submit" value="Submit">
</form>
%%[ ENDIF ]%%
<script runat="server">
}catch(e){
Write(Stringify(e));
}
</script>

To see this script in action, visit my CloudPage here.


Questions? Comments?

Leave a comment below or email me at zuzanna@sfmarketing.cloud.


8 thoughts on “Working with Salesforce Multi-Select Picklists in AMPscript

  1. Mishi

    Hello Zuzanna ,
    The code I am working on is nearly on similar lines. It worked well until my cloud page does not allow me to do “fieldsToNull” if I deselect all the picklist values in my form and throws an error –

    {“message”:”Call to update the salesforceobject contact ID = 0037U00000Cx4aiQAB failed! Item has already been added. Key in dictionary: ‘fieldsToNull’ Key being added: ‘fieldsToNull'”,”description”:”ExactTarget.OMM.FunctionExecutionException: Call to update the salesforceobject contact ID = 0037U00000Cx4aiQAB failed! Item has already been added. Key in dictionary: ‘fieldsToNull’ Key being added: ‘fieldsToNull’\r\n Error Code: UPDATESINGLESFOJBECT_FUNC_ERROR\r\n – from Jint\r\n\r\n”}

    Kindly let me know what I might be doing wrong

    Like

  2. Mishi

    Just to inform, this field of mine is a “Interest__c” field in sales cloud and updates like (cycling;swimming;running).
    Also, this “fieldsToNull” worked fine in case of checkbox (boolean data type) in sale cloud. e.g. SMS_opt_out_c = “False”.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s