A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Per Hemmingson
Jun 16, 2009
  11394
(0 votes)

Do you want Community features on your CMS pages? PageEntity to the rescue

For a while now you have been able to rate articles and blog posts, as well as see most viewed, most popular and a Tag Cloud for each. These items are standard CMS pages but with a custom made EPiServer Community Module hooked up, aka PageEntity.

However, this blog post will not go into detail on how to create a community module cause it is better explained in detail in Joel Abrahamsson’s article series on the subject. Read it first and you will better understand this PageEntity module.

We started of simple and created the PageEntity class for all our objects, and then we could pass in what type of page it is (article, blog, standard, etc) to the constructor. Well we created PageEntityTypes enum to handle it (the observant one can see that not all of them are implemented live yet)

   1: public enum PageEntityTypes
   2: {
   3:         Undefined = 0,
   4:         ForumThread = 1,
   5:         ForumPost = 2,
   6:         Article = 3,
   7:         Documentation = 4,
   8:         VideoPage = 5,
   9:         DownloadPage = 6,
  10:         FAQ = 7,
  11:         StandardPage = 8,
  12:         BlogItem = 9,
  13:         CodeSample = 10
  14: }

 

Then for example to Tag an existing Article page looks like this:

   1: // check if pageentity exists for this page, if not, create it
   2: if (CurrenPageEntity == null)
   3: {
   4:     CurrenPageEntity = new PageEntity(CurrentPage.PageGuid, Enums.PageEntityTypes.Article);
   5:     CurrenPageEntity.EntityTags.Add(new EntityTag(new Tag(txtTagBox.Text), new UserAuthor(writerIUser)));
   6:     CurrenPageEntity = PageEntityHandler.AddPageEntity(CurrenPageEntity);
   7: }

The code above assumes you have a PageEntity property named CurrentPageEntity.

However this approach soon appeared to be not good enough. It worked for most situations except when you wanted a Tag Cloud of Article type.
Version 0.2 was to make PageEntity class abstract and create about 9 subclasses of it to get a specific type. Below example for a EPiServer famous standard page

   1: public class StandardPageEntity : PageEntity
   2: {
   3:    public StandardPageEntity(Guid pageGuid, EPiServer.Common.ISite site):base(pageGuid, site, PageEntityTypes.StandardPage){}
   4:    public StandardPageEntity(int id, int siteId, Guid pageGuid) : base(id, siteId, pageGuid, PageEntityTypes.StandardPage) { }
   5: }

 

The CurrentPageEntity moved to a base class to handle all pages entity types, it got a little large for a property…

   1: public PageEntity CurrentPageEntity
   2: {
   3:     get
   4:     {
   5:         if ((_currentPageEntity == null && ViewState["currentPageEntityGUID"] != null))
   6:         {
   7:             _currentPageEntity = PageEntityHandler.GetPageEntityByGUID((Guid)ViewState["currentPageEntityGUID"]);
   8:         }
   9:         
  10:         if (_currentPageEntity == null)
  11:         {
  12:             _currentPageEntity = PageEntityHandler.GetPageEntityByGUID(CurrentPage.PageGuid);
  13:         }
  14:  
  15:         // check that pageEntity is enabled on current page
  16:         if (!EnableVisit || !EnableTagging || !ShowRating)
  17:         {
  18:             return null;
  19:         }
  20:  
  21:         // check that current site has been inititalized and defined
  22:         if(SiteHandler.CurrentSite == null)
  23:         {
  24:             throw new EPiServerException("Current site is null - cannot create Page Entity");
  25:         }
  26:  
  27:         // if still null create it
  28:         if (_currentPageEntity == null)
  29:         {
  30:             _currentPageEntity = (PageEntity)Activator.CreateInstance(PageEntityUtils.GetPageEntityType(CurrentPage), CurrentPage.PageGuid,
  31:                                                           SiteHandler.CurrentSite);
  32:             
  33:             _currentPageEntity = PageEntityHandler.AddPageEntity(_currentPageEntity);
  35:         }
  36:         return  _currentPageEntity;
  37:     }
  38:     set
  39:     {
  40:         _currentPageEntity = value;
  41:         ViewState["currentPageEntityGUID"] = (value != null) ? (object)value.PageGUID : null;
  42:     }
  43: }

We wanted the website editors to enable/disable PageEntity function on parts of the site, hence the EnableVisit, EnableTagging and ShowRating dynamic properties above. On the World we also use several community sites, therefore check of SiteHandler.Currentsite. We also determined to reference all pages by PageGuid to be on the safe side.

 

The method PageEntityUtils.GetPageEntityType is very simple, it helps determine what type of page it is. Example for wiki page:

   1: public static Type GetPageEntityType(PageData CurrentPage)
   2: {
   3:  
   4:     if (CurrentPage.PageTypeName == "[Wiki] Article")
   5:     {
   6:         return typeof (WikiArticlePageEntity);
   7:     }
   8:  
   9:     return null;
  10: }

 

You have to handle deleted pages with a PageEntity reference. Our choice was to create a httpmodule (PageEntityEventHandler.cs) and remove it.

Integrate it is quite easily, I added it to a Relate+ /wikiX site in about 10 minutes.  Which you can see on the updated wikiX for Relate+ version on codeplex.
in the supplied

file you see how we added it to the WikiX article page.

  • Add the cs. files to your project,
  • Run the supplied sql script to create tblPageEntity and the stored procedures
  • Then modify your code to create PageEntity of your choice. (Update *enum, *subclasses, *utils)

 

Feedback and suggestions for improvement is welcome. Remember this module is not supported by EPiServer. It just demonstrates how to apply EPiServer Community features on CMS pages.
In a not so distant future release of the community you will also be able to comment your page entities. Sweet?!

Cudos to greger and erik who was involved in creating the PageEntity.

Jun 16, 2009

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026

Scheduled job for deleting content types and all related content

In my previous blog post which was about getting an overview of your sites content https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/1/sche...

Per Nergård (MVP) | Jan 30, 2026

Working With Applications in Optimizely CMS 13

💡 Note:  The following content has been written based on Optimizely CMS 13 Preview 2 and may not accurately reflect the final release version. As...

Mark Stott | Jan 30, 2026

Experimentation at Speed Using Optimizely Opal and Web Experimentation

If you are working in experimentation, you will know that speed matters. The quicker you can go from idea to implementation, the faster you can...

Minesh Shah (Netcel) | Jan 30, 2026