Sync and replicate pages between sites

Sync page properties between Optimizely sites

In this blog post I describe how you can sync and replicate pages and properties between different Optimizely sites using ContentDelivery Api.

icon of user profile
By OMVP Luc Gosso

Published 29th dec 2022
CMS v11 and v12

Prerequisits/todo list

  • Site S1 is the mother site - i want to replicate page type PT1, PT2, PT3 to another site(s)
  • Site S2 is a child site - this site imports the page types above
  • S1 and S2 are not in same vs-solution
  • S1 needs to install Episerver.ContentDeliveryAPI (v2 for CMS 11) latest version for CMS 12
  • S1 has Episerver.FIND configured and therefor i've installed Episerver.ContentDelivery.Search (needed for this solution)
  • S2 is CMS12 and has Epicweb.Optimizely.ContentDelivery.Sync downloaded from github and attached as a project to the main web csproj.
  • S2 has the ImportAndSyncJob.cs from github in it's main web csproj
  • S2 - copy the Pagetypes (cs files) PT1, PT2 and PT3 to this proj from S1

Download code from Github

https://github.com/Epicweb-Optimizely/Epicweb.Optimizely.ContentDelivery.Sync

Configuration details

Follow the prerequisits/todo list above first

Startup registration

Register the services, point url to mother site, we're useing appsettings file.

services.AddSingleton<IImportApiClient, ImportApiClient>(sp =>
{ // add url and token for contentdeliveryapi to the mother site
return new ImportApiClient(Startup.StaticConfig.GetValue<string>("CustomSync:accesstoken"),Startup.StaticConfig.GetValue<string>("CustomSync​:url"));
}); //example appsettings "url": "https://www.myOptiSite.com",

services.AddTransient<ISerializeService, SerializeService>();​

services.AddSingleton<ContentDeliveryMapper>();

​​ImportAndSyncJob.cs​

We can use GetPageModels to get pages by pagetypes from mother site, this function is useing Find search to get all pages of these types.

var pages = _serializeService.GetPageModels(
new string[] { "StandardPage", "ProductPage" },// names of pagetypes you want to import
propsToSync: null); // new string[] { "fax", "longitude", "telephone", "visitReservationXHtml", "VideoConferencing", "extraAddress1City" }); //list of props you want to import, if null, import all, this will not create new props, then need to be in code​

Mapping helper between ContentDelivery format to pagetypes

_contentDeliveryMapper.Map(page: page, pageModel: pageModel, methodSpecialSerialization: null);

Special Serialization of custom properties (ListProperty)

In this example we have a list property of model OpenTime

Model:

public class OpenTime
{
[Display(Name = "Week")]
public string WeekDays { get; set; }
[Display(Name = "End")]
public string WeekEnds { get; set; }
[Display(Name = "Note")]
public string Note { get; set; }
}

Use mapper like this:

_contentDeliveryMapper.Map(page: page, pageModel: pageModel, methodSpecialSerialization: SerializeCustomPropertyLists);

Example CustomPropertySerializer:

public object SerializeCustomPropertyLists(string propertyDataType, System.Text.Json.JsonElement jsonElement)
{
switch (propertyDataType)
{

case "OpenTimeListProperty":
return jsonElement.ValueKind != JsonValueKind.Null ? jsonElement.Deserialize<IList<OpenTime>>(new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }): null;
default:
break;
}
return null;
}

How about ContentReference and ISelectionFactory properties?

Yes, use [SyncPageName],  it will take the contentref and get the PageName of the IContent

Example

On mother site i might look like this:

[Display(GroupName = SystemTabNames.Content, Order = 23)]
[UIHint(SiteUIHints.Regions)]
[Required]
public virtual string Regions { get; set; }

UI:

Regions example as dropdown

On child site:

[Display(GroupName = SystemTabNames.Content, Order = 23)]
[SyncPageName]
public virtual string Regions { get; set; }

UI:
example UI child site, regions as text

This only works for ContentReference or lists of ContentReference

Extensible

Since it is not a plugin, and the code is on github and implemented to your solution, it is simple to extend. Feel free to contribute with new functionality.

Other approaches to consider

We are using content replication, this is one way of doing it, the pros with this content replication strategi was we wanted to sync some propertys on mother site, but wanted to be able to have extended properties in child site on same page model.

You should consider these alternatives to content replication:

Pros and cons Content Provider/Content replication

Allan has described it well: Content Provider or Content Replication (codeart.dk)

EOF

Thank you for reading,

Happy coding!

Luc

About the Author

Luc Gosso

OMVP Luc Gosso

– Independent Senior Web Developer
working with Azure and Optimizely