Episerver CMS Cheat Sheet

During the time I worked with CMS, I built up list of some cool stuff. I thought to share them with you. Maybe in future we can have a Episerver CMS/Commerce cheat sheet or knowledge based in Github so we can all use them. This is just beginning 🙂

==========================CUSTOM LINK ITEM COLLECTION RENDERING=====================================
    @Html.PropertyFor(m => m.MainBody)

    // FullRefreshPropertiesMetaData asks on-page edit to reload the page 
    // to run the following custom rendering again after the value has changed.
    @Html.FullRefreshPropertiesMetaData(new []{ "RelatedContentLinks" })

    // EditAttributes enables on page-edit when you have custom rendering.
    <p @Html.EditAttributes(m => m.CurrentPage.RelatedContentLinks) >
    @if (Model.CurrentPage.RelatedContentLinks != null)
        <span>See also:</span>
        foreach (LinkItem item in Model.CurrentPage.RelatedContentLinks)
            <a href="@item.Href">@item.Text</a>

    @Html.PropertyFor(m => m.MainBody)

    <h2>Releated Content</h2>
    @Html.PropertyFor(m => m.CurrentPage.RelatedContentLinks, "SeeAlso")
public class ArticlePage : PageData

    public virtual LinkItemCollection RelatedContentLinks { get; set; }


global folder for the media and block -> EPiServer.Core.SiteSettings.Current.GlobalBlocksRoot
site folder for the media and block EPiServer.Core.SiteSettings.Current.SiteBlocksRoot
IContentLoader (just readonly) vs IContentRepository  (CRUD) vs DataFactory (legacy, backward compatibility)

- Attributes:
Content Types: [ContentType], [Access], [AvailableContentTypes], [ImageUrl]

Property: [Display(
            Name = "Classification",
            Description = "Genre or type of article.",
            GroupName = "Details", Order = 2)]
public static class GroupNames
   [Display(GroupName="MyNews", Order=1)]
   public const string News = "News";
   public const string Contact= "Contact";

Version status 
	NotCreated. The version has not been saved yet.
	CheckedOut. The currently edited version
	AwaitingApproval. The editor is done and has marked the version as ready for approval
	Rejected. The version did not pass the approval
	CheckedIn. The version is approved and ready for publish
	DelayedPublished. The version will be automatically published at a future date and time
	Published. The version is published
	PreviouslyPublished. The version has been published but is now replaced with a different version
Status transitions
	Default/None. Saves a version maintaining the current status unless a new version is created. In this case the new version is created in a checked out state. (Default has replaced None in CMS 10)
	Publish. Publishes a version.
	Schedule. Schedule a version for automatic publishing at a later date. (New in CMS 10)
	CheckOut. Checks out a version to indicate that it is being worked on. (New in CMS 10)
	CheckIn. Checks in a version indicating that it is ready to be published
	RequestApproval. Saves a version to a state indicating that it is ready to be approved
	Reject. Rejects a version. This is normally done during an approval review.
	Save. Save action which outcome will depend on the current status. Will in some cases maintain the status and in other cases check out the current version.
Optional parameter
	ForceNewVersion. Specifies that the content saved should be created as a new version.
	ForceCurrentVersion. Specifies that the save should update the existing version.
	SkipValidation. Specifies that the content should be saved without performing the usual validation.
	SkipSetCommonDraft. Specifies that the version should not be set as common draft (the version used by default in the CMS edit user interface)
	DelayedPublish. Used in combination with SaveAction. CheckIn to specify that the version should be automatically published at a future date and time. (Deprecated in CMS 10)

force to save/publish by anonymouse user (e.g. schedule job) contentRepository.Save(myPage, EPiServer.DataAccess.SaveAction.Publish, EPiServer.Security.AccessLevel.NoAccess);

custom icon for content type:

public class ContainerPageUIDescriptor : UIDescriptor<ContainerPage>
	public ContainerPageUIDescriptor()
		: base("epi-iconObjectPage")

change the default view

	public class StartPageUIDescriptor : UIDescriptor
		public StartPageUIDescriptor(): base(ContentTypeCssClassNames.Page)
			DefaultView = CmsViewNames.AllPropertiesView;
			EnableStickyView = false;
change the default icon of media


public class DocumentUIDescriptor : UIDescriptor<Document>
    public DocumentUIDescriptor() : base("icon-document")
        DefaultView = CmsViewNames.AllPropertiesView;
change editor descriptor

	[EditorDescriptorRegistration(TargetType = typeof(string))]
	public class StringEditorDescriptor : EditorDescriptor
		public StringEditorDescriptor()
			ClientEditingClass = "dijit.form.ValidationTextBox";


The EPiServer.Web.TemplateResolver.TemplateResolving event is raised. If an event handler selects a template, that template is used with no further handling.
All templates matching the desired content type are filtered according to the rendering mode: If t is a page, a suitable controller is selected; if it is partial rendering, a suitable partial controller or partial view is selected. For partial templates, the list is filtered according to main template.
If the template is requested with a specific tag, the list is filtered on that tag. If no template matching the tag exists, all templates from 2 are taken into account.
If any display channel is active, and there are template tags matching that channel, templates are filtered for DisplayChannel. 
From remaining templates, the shortest inheritance chain to the TemplateModel marked as Default and not inherited, is selected.
If no match from 5, the shortest inheritance chain to TemplateModel that is marked as Default, is selected.
If no match from 6, the shortest inheritance chain to TemplateModel, is selected.
The EPiServer.Web.TemplateResolver.TemplateResolved event is raised, providing a chance to replace the selected template.

--------------------------custom root folder for block selector----------------------------
public virtual ContentReference TeaserBlockReference { get; set; }

[EditorDescriptorRegistration(TargetType = typeof(ContentReference), UIHint = "teaserblock")]
public class BlockReferenceEditorDescriptor : ContentReferenceEditorDescriptor<TeaserBlock>
    public override IEnumerable<ContentReference> Roots
            //Sample to override the default root for the repository.
            //Take the reference from configuration or site initialization and do not hard-code it.
            return new ContentReference[] { new ContentReference(90 ) };



- Protecting a controller via a permission

   [AuthorizePermission("MyCustomPermissions", "EditSettings")]
    public class EditSettingsController : Controller
        public ActionResult Index()
            return View();

    public static class MyCustomPermissions
        public const string GroupName = "MyCustomPermissions";

        static MyCustomPermissions()
            EditSettings = new PermissionType(GroupName, "EditSettings");
            ViewSettings = new PermissionType(GroupName, "ViewSettings");

        public static PermissionType EditSettings { get; private set; }

        public static PermissionType ViewSettings { get; private set; }
Property settings:

[EPiServer.Core.PropertySettings.PropertySettings(typeof(CustomStringSettings), true)]
public class CustomPropertyString : PropertyString

    public class PlugInInitialization : IInitializableModule
        public void Initialize(InitializationEngine context)
            PropertyControlClassFactory.Instance.RegisterClass(typeof(PropertyString), typeof(CustomPropertyString));
            PropertyControlClassFactory.Instance.RegisterClass(typeof(PropertyLongString), typeof(CustomPropertyString));

        public void Uninitialize(InitializationEngine context)

Episerver CMS 11 – Certification

If you are Episerver CMS Certified Developer, every two year you need to the exams. And this month was my turn! I started to look around and found many stuff related to exam changed. To summarized it I gathered all items I thought is important to read and summarized them as below. But this doesn’t mean you should not read whole Episerver World documentation!

Product Knowledge

Learning path


Installation, Operation, and Configuration
Environment & Deployment
Error handling
License model
DXC Service

Content Model
Content types and models
Content approvals
A/B testing

Creating Websites
Technical architecture
Authentication and authorization
Globalization and localization
Performance and scalability
Data storage
Indexed search

Advanced Concepts
Scheduled jobs
Initialization modules
Extending the Episerver UI & Plugin
Content providers


Breaking changes in the past two major releases

New features in the past two major releases

  • https://world.episerver.com/documentation/Release-Notes/?packageGroup=CMS
  • https://world.episerver.com/features/

Episerver – Sydney Meetup – 27 Feb 2019

We are so pleased to announced our next Episerver Meetup 🙂

This is very exciting as this meetup will be held in Episerver office in Sydney and more exciting which Damien Dias from Episerver is going to speak about the upgrade process. This is what we are dealing many times! So would be really helpful to see his best practices and advises!

Next Nicola Ayan EMVP is going to talk about how you can build multi-step forms with conditional logic branches using Episerver Forms 🙂 I myself is love to learn it 🙂

And finally I speak about the Web Bots and run an example to show how Bot can be integrated with Episerver Commerce!

We are really excited about this and I hope to see you all SOOON!

Please RSVP ASAP using link bellow!



LATE Spring Sydney Episerver Meetup!

Studio 60 is going to host next Episerver meetup in Sydney and heaps of good things are going to happen.

Damien Dias from Episerver would present about his awesome experience with Upgrading OLD Episerver website to a new one. It is awesome that we hear someone is with Episerver for a long time and now want to invest for the future and upgrade the existing site and as a technical guru you need to know best practices to make sure customer will get best out of the upgrade!


Second Nicola our EMVP will present how we can take Episerver Form to next level and make it as a wizard which each step is conditional and based on the previous user answer we give more relative steps!


And myself (if there is enough time) love to speak about how we can easily connect an existing Episerver eCommerce website (read it Quicksilver) to Azure Web Bot! Cool ha!! I love bots as they are the more human type of thing instead of a web page! To me, the future of the internet is a bot!


Please RSVP HERE as we have limited sit 🙂 and it is FREE plus we have pizza and beer!

DDD Sydney Outcome – Episerver CMS Headless

DDD is a great conference which is an inclusive non-profit conference ran by the community. I was so lucky this year to be part of this awesome conference and present our lovely Episerver which most of the developers there never heard of it! Means we need to create a better community out there. I presented Episerver CMS Headless and to spice it up added Microsoft Cognitive Services. My aim for the talk to build a website that can serve user as a Bot as well. To achieve this I used Episerver CMS as backend and Headless part to expose CMS data:



And used LUISE to interpret users request and Microsoft Cognitive Service to route the request as the picture below:


Santa is the user by the way!!!


To recap how this is working is Microsoft Web Bot is part of Cognitive Service and allow the user to interact with your application using different channels. So you don’t need to worry about exposing your app to different channels (e.g. Cortana, Microsoft Teams, Skype, Online Web Chat, ..). How? As below:


You just need to implement one function to get the data from user:



And Bot Service will send you all you need as an Activity if you want to read more detail about it read here. And what we do is get what user asked and process it.

First Step would understand user’s intent, so we need AI and as I’m lazy and love online services I would use LUIS which is Language Understanding online tool from Microsoft. The way it works is quite simple:

Input: String


  • Intent -> User goal
  • Entities -> Keywords that our application cares


Input: Book me a flight to Cairo


  • Intent -> “BookFlight”
  • Entities
    • “cairo” – “location”


So you may ask how the hell LUIS knows what is “BookFligh” and how to it knows the entities. In a short-term, you need to teach LUIS! How? Read here.

Now we know what user wants and knows all related keywords, so the next step is using Episerver Headless CMS API to fetch what user wants:



if you like to read more detail about it you can reference Episerver documentation or a series of my blog posts. Bellow is how it looks like:



And rest is easy! Just interpret the data and return it back to the client. You can get the whole source code using links below:


Episerver CMS: https://github.com/zanganeh/SydMeetup.PlacesDirectory

Cognitive Service: https://github.com/zanganeh/SydMeetup.PlacesDirectory.Bot


And if you are interested in the presentation please find it here

Wrap Up – Third Sydney Episerver Meetup

First I want to say thanks @Nicola and 1990 Digital and Episerver for hosting this session. I learned a lot and I’m started starving for the next meetup!


Nicola spoke about her new tool ‘EpiserverCmsAudit’. This tool is really awesome and can help you to find the usage of your content type. Very nice dashboard and very easy to install and it is FREE! So if you to give it a go to her post to read more about it and you can take a look at the source code or just install the Nuget package This is quite a bit awesome while website moving to DXC as they can build many websites and many contents! So with this tool, you as a dev, tester or content editor can make sure your change impact on all aspect of your app! GREAT JOB!


I spoke about Episerver Headless CMS, eCommerce and how you can integrate that with Microsoft Web Bot. This would be important as Bots are more human-friendly – having said that the concept is still at a very early stage. The concept is quite simple, Web Bot gets the query from user pass to Luis.ai and passes the action to Episerver to get the data back and pass it back to Bot! If you feel like you need more info, you can download the presentation and the source code of the bot can be found here and the bot source code can be found here. If you are interested and still have a question just comment here!

I’m going to speak about this in more detail in DDD, so if you keen to learn more you just need to get the ticket!

DDD Sydney – Episerver session (Headless CMS!)

Next, DDD Sydney would be on 18th of August and my proposed session about Headless CMS is not on the vote! I need you Episerver gurus help to help me get my session approved. DDD has cool concept off democratically selected agenda. So all submitted agendas would be on the vote and YOU!!! can help me my session be presented by voting. Obviously, if you like it!

To vote you please:

  • click on THIS LINK
  • Wait until the page fully loaded (the list of sessions is quite big and use AJAX to load).
  • When the page loaded (you can see the list of sessions), search for term ‘future’


  • This is my session and if you like to vote, please click on ‘Vote’. You can select more than one item, so clicking on ‘Vote’ doesn’t mean you are done (SORRY I KNOW IT IS HASSLE!)
  • When your vote is selected you need to click on ‘Submit Votes’

  • And if you get a success message, you are DONE!



Third Sydney Episerver Meetup

Our third meetup is going to more focus on innovation. 1990 Digital will host our meetup this time.

Nicola is the technical lead and working very closely with customer and know customer tears! She will speak about the new tool she built that impressed her customer and think would impress you as a developer as well!! ‘Episerver CMS Audit’ will help developers to visualize the content instances and content type dependencies and can help developers to find out more about how their content type is being used. Especially on the complex multi-site environment which you end up many content types, this tool would help testing of the site much easier.

I’m going to speak about headless CMS with a good example. This practice can help to understand the Episerver Content Deliver API structure little a bit better and how that fits into the mobile app! and finally, as Nicola proposed we want to see the marriage of Episerver CMS Alloy sample and Cortana (Microsoft virtual assistant) and show how content deliver API can fit into new content channels!

Hope to see you all there. Please register here.

Content as a Service and Episerver – Part 3 – Content Delivery API

Episerver Content Delivery API empowers you to expose your content via HTTP protocol. This enables  Recently Episerver enterprises to use their content in the mobile apps or any third party which needs the content of your website. Episerver released a beta version of Content Delivery API recently and can be used via Nuget Package. This would be a big step for Episerver to add the ability to Enterprises to go toward the concept of Content as a Service (CaaS).

What features does it have? It allows you to expose all content of your site via HTTP using JSON

That scary!? Na, you already exposing your content via HTTP using a browser! That is correct, some content is restricted content and should be exposed to all and that is facilitated by authenticating users via OAuth.

Query the content, that could be slow? The API will leverage Episerver Find to query the content and this means query will be run efficiently without affecting your website performance.

Mmm..So what I need to have to start? It is quite simple, create new Episerver Alloy Sample and go through below steps:

In this stage Episerver Content Delivery API would be just one package but I expect this would be change

  1. Register a new Episerver Find service and put the content into the sample website
  2. Install Content Delivery API Nuget Package
     Install-Package EPiServer.ContentDeliveryApi
  3. Add below code to your ‘ConfigureContainer’ function:
    GlobalConfiguration.Configure(config =>
        config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.LocalOnly;
        config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings();
        config.Formatters.XmlFormatter.UseXmlSerializer = true;
        config.DependencyResolver = new StructureMapResolver(context.StructureMap());