Sync Salesforce field values into Sitecore facets

S4S can be used to sync Salesforce field values to Sitecore contact facets.

The following code sample is an example of how to retrieve Salesforce entities using a SOQL query and set the values to Sitecore contact facets. This can be extended into a complex solution to cater to any kind of sync scenario between Salesforce entity fields and Sitecore contact facets depending on your requirements.  

There are few more things to note before diving into the code.

  • You need to define a valid SOQL query according to your requirements to return any number of fields. Make sure to include all the Salesforce fields you would like to map into Sitecore facets in this query.

  • The code sample that maps the Salesforce fields to Sitecore contact facets is below. This example writes Salesforce field values into the “Personal” and “S4SInfo” facets in the Sitecore contact.

To meet another requirement, change the SOQL query to retrieve the relevant Salesforce fields then map them to any type of Sitecore contact facet.

Salesforce field name

Sitecore contact facet key

Sitecore contact facet field name

FirstName

Personal

FirstName

LastName

Personal

LastName

Title

Personal

Title

Birthdate

Personal

Birthdate

Description

S4SInfo

Fields

MobilePhone

S4SInfo

Fields

LeadSource

S4SInfo

Fields

  • The code sample uses Sitecore alias id to retrieve the Sitecore contacts. The Sitecore alias id recognizes the same individual arriving on the website from different devices and is compatible with S4S out-of-the-box form save action scenarios, S4SLB, and personalization. Again, you can change this according to your requirements.

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 using FuseIT.S4S.WebToSalesforce.Connection; using FuseIT.Sitecore.Personalization.Facets; using FuseIT.Sitecore.Salesforce; using FuseIT.Sitecore.SalesforceConnector; using FuseIT.Sitecore.SalesforceConnector.Entities; using FuseIT.Sitecore.SalesforceConnector.Services; using Sitecore.XConnect; using Sitecore.XConnect.Client; using Sitecore.XConnect.Client.Configuration; using Sitecore.XConnect.Collection.Model; using System; using System.Collections.Generic; using XConnect = Sitecore.XConnect; using BaseSitecore = Sitecore; namespace FuseIT.S4SSyncc.Demo { public class SyncSalesforceToSitecore { public const string SFFieldName_FirstName = "FirstName"; public const string SFFieldName_LastName = "FirstName"; public const string SFFieldName_Title = "Title"; public const string SFFieldName_Birthdate = "Birthdate"; public const string SFFieldName_SitecoreAliasId = "FuseITAnalytics__SitecoreVisitorId__c"; public const string SFFieldName_Description = "Description"; public const string SFFieldName_Mobile = "MobilePhone"; public const string SFFieldName_LeadSource = "LeadSource"; public void SyncSaleforceFieldsIntoSitecoreContactFacetsNew() { //Define the SOQL query to retrieve Salesforce objects. Make sure to include all the Salesforce field names which need get the values from in order to set them into Sitecore facets. //If you do not define the Salesforce field names in this SOQL query which you intent to read later, code will not bring back those Salesforce fields or values. var soqlQuery = @"Select c.Id, c.FirstName, c.LastName, c.Birthdate, c.Title, c.Description, c.MobilePhone, c.LeadSource, c.FuseITAnalytics__SitecoreVisitorId__c from Contact c where LastModifiedDate >= LAST_N_DAYS:1"; //Define Salesforce entity type. This type should match with the SOQL query above. var sfObjectType = "Contact"; //Define S4S connection string name. Default one would be "S4SConnString". var s4sConnectionStringName = "S4SConnString"; //Get Salesforce session var salesforceSession = SalesforceSessionCache.GetSalesforceSession(s4sConnectionStringName); //Get relevant Salesforce entities according to the SOQL query. var sfEntityList = GetSFEntitiesBySOQLQuery(salesforceSession, sfObjectType, soqlQuery); foreach (var sfEntity in sfEntityList) { var sitecoreAliasId = (sfEntity.InternalFields.Contains(SFFieldName_SitecoreAliasId)) ? sfEntity.InternalFields[SFFieldName_SitecoreAliasId] : string.Empty; if (!string.IsNullOrEmpty(sitecoreAliasId)) { //Read relevant Salesforce field values var firstName = (sfEntity.InternalFields.Contains(SFFieldName_FirstName)) ? sfEntity.InternalFields[SFFieldName_FirstName] : string.Empty; var lastName = (sfEntity.InternalFields.Contains(SFFieldName_LastName)) ? sfEntity.InternalFields[SFFieldName_LastName] : string.Empty; var title = (sfEntity.InternalFields.Contains(SFFieldName_Title)) ? sfEntity.InternalFields[SFFieldName_Title] : string.Empty; DateTime birthdate = (sfEntity.InternalFields.Contains(SFFieldName_Birthdate)) ? sfEntity.InternalFields.GetField<DateTime>(SFFieldName_Birthdate) : DateTime.MinValue; var description = (sfEntity.InternalFields.Contains(SFFieldName_Description)) ? sfEntity.InternalFields[SFFieldName_Description] : string.Empty; var mobilePhone = (sfEntity.InternalFields.Contains(SFFieldName_Mobile)) ? sfEntity.InternalFields[SFFieldName_Mobile] : string.Empty; var leadSource = (sfEntity.InternalFields.Contains(SFFieldName_LeadSource)) ? sfEntity.InternalFields[SFFieldName_LeadSource] : string.Empty; using (XConnectClient client = SitecoreXConnectClientConfiguration.GetClient()) { try { //Include all the Sitecore facet keys which you would like to read/write. //For this example, following code will retrieve "Personal" and "S4SInfo" facets. var facetNameArray = new string[] { PersonalInformation.DefaultFacetKey, S4SInfo.DefaultFacetKey }; //Retrieve Sitecore contact by alias id IdentifiedContactReference reference = new IdentifiedContactReference(XConnect.Constants.AliasIdentifierSource, sitecoreAliasId); var sitecoreContact = client.Get<XConnect.Contact>(reference, new ContactExecutionOptions(new ContactExpandOptions(facetNameArray))); if (sitecoreContact != null) { Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Existing Sitecore contact found for source: {XConnect.Constants.AliasIdentifierSource} and Identifier: {sitecoreAliasId}."); #region SETTING PERSONAL FACET - FirstName, LastName, Title, Birthdate //Set FirstName, LastName, Title and Birthday fields in PersonalInformation facet var personalFacet = sitecoreContact.Personal() ?? new PersonalInformation(); if (!string.IsNullOrEmpty(firstName)) { personalFacet.FirstName = firstName; Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Values set to the personal information facet FirstName - [{firstName}]."); } if (!string.IsNullOrEmpty(lastName)) { personalFacet.LastName = lastName; Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Values set to the personal information facet LastName - [{lastName}]."); } if (!string.IsNullOrEmpty(title)) { personalFacet.Title = title; Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Values set to the personal information facet Title - [{title}]."); } if (birthdate != DateTime.MinValue) { personalFacet.Birthdate = BaseSitecore.DateUtil.ToUniversalTime(birthdate); Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Values set to the personal information facet Birthdate - [{birthdate.ToString()}]."); } client.SetPersonal(sitecoreContact, personalFacet); #endregion #region SETTING S4SINFO FACET - LeadSource, MobilePhone, Description //SET LeadSource, MobilePhone and Description values in dictionary facet field called Fields in S4SInfo facet. var s4SFacets = sitecoreContact.GetFacet<S4SInfo>(S4SInfo.DefaultFacetKey) ?? new S4SInfo(); if (!string.IsNullOrEmpty(description)) { if (s4SFacets.Fields.ContainsKey("Description")) { s4SFacets.Fields["Description"] = description; } else { s4SFacets.Fields.Add("Description", description); } Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Add/edit following key value pair to the Field dictionary in S4SInfo facet: Key-[Description], Value-[{description}]."); } if (!string.IsNullOrEmpty(mobilePhone)) { if (s4SFacets.Fields.ContainsKey("MobilePhone")) { s4SFacets.Fields["MobilePhone"] = mobilePhone; } else { s4SFacets.Fields.Add("MobilePhone", mobilePhone); } Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Add/edit following key value pair to the Field dictionary in S4SInfo facet: Key-[MobilePhone], Value-[{mobilePhone}]."); } if (!string.IsNullOrEmpty(leadSource)) { if (s4SFacets.Fields.ContainsKey("LeadSource")) { s4SFacets.Fields["LeadSource"] = leadSource; } else { s4SFacets.Fields.Add("LeadSource", leadSource); } Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Add/edit following key value pair to the Field dictionary in S4SInfo facet: Key-[LeadSource], Value-[{leadSource}]."); } //Set S4S dictionary facet client.SetFacet(sitecoreContact, S4SInfo.DefaultFacetKey, s4SFacets); #endregion // Submits the batch. client.Submit(); } else { Logging.Debug(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): No existing Sitecore contact found for source: {XConnect.Constants.AliasIdentifierSource} and Identifier: {sitecoreAliasId}."); continue; } } catch (Exception ex) { Logging.Error(this, $"{nameof(SyncSaleforceFieldsIntoSitecoreContactFacetsNew)}(): Exception occured when retrieving/updating Sitecore contact with Sitecore alias id: {sitecoreAliasId}", ex); continue; } } } } } /// <summary> /// Retrieve Salesforce entities by SOQL query /// </summary> /// <param name="sfSesion"></param> /// <param name="sfEntityType"></param> /// <param name="soqlQuery"></param> /// <returns></returns> private List<GenericSalesforceEntity> GetSFEntitiesBySOQLQuery(SalesforceSession sfSesion, string sfEntityType, string soqlQuery) { var sfEntityList = new List<GenericSalesforceEntity>(); try { Logging.Debug(this, $"{nameof(GetSFEntitiesBySOQLQuery)}(): EntityType: {sfEntityType} SOQLQuery: {soqlQuery}, "); var genericSFService = new GenericSalesforceService(sfSesion, sfEntityType); sfEntityList = genericSFService.GetBySoql(soqlQuery); } catch (Exception ex) { Logging.Error(this, $"{nameof(GetSFEntitiesBySOQLQuery)}(): An error occured when retrieving Salesforce entities using SOQL query.", ex); } return sfEntityList; } } }

To regularly sync the two systems, hook this method into a Sitecore scheduled task.