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

Anders Hattestad
Jun 14, 2012
  3935
(0 votes)

Find pages a lot faster without using FindPagesWithCriteria

I have in some projects had the need to get different pages from all over my site with some criteria’s. This could have been a job for FindPagesWithCriteria, but I was a bit concerned about the performance. I therefore made myself a Dynamic DataStore table that have those page data properties I want to query against with queries like this

  1. var q = from item in Items where
  2.             item.BoolProperties.Contains("PageVisibleInMenu")
  3.         orderby item.StartPublish
  4.         select item;

Every time a page is published, moved or deleted I update the store. If the page is the master language I also update the other languages. This was actually the tricky part. With replacement languages on like this

image

The page.PageLanguages only returns the languages the page have values on. Therefore one have to get all those language pages like this:

  1. PageDataCollection languageBranches = DataFactory.Instance.GetLanguageBranches(page.PageLink);
  2. foreach (LanguageBranch current2 in LanguageBranch.ListEnabled())
  3. {
  4.     if (current2.LanguageID.ToUpper() != page.MasterLanguageBranch.ToUpper())
  5.     {
  6.         PageLanguageSetting pageLanguageSetting2 = PageLanguageSettingsTree.Instance.Get(page.PageLink, current2.LanguageID);
  7.         bool flag = languageBranches.Exists(page.PageLink, current2.LanguageID);
  8.         if (flag || (pageLanguageSetting2 != null && pageLanguageSetting2.IsActive))
  9.         {
  10.  
  11.             var page3 = EPiServer.DataFactory.Instance.GetPage(page.PageLink, LanguageSelector.Fallback(current2.LanguageID, true));
  12.             if (page3 != null)
  13.             {
  14.                 if (page3.IsDeleted)
  15.                     DeletePage(page3.PageLink, current2.LanguageID);
  16.                 else
  17.                     UpdatePage(page3, current2.LanguageID);
  18.             }
  19.  
  20.         }
  21.     }
  22. }

The actually DDS table have some known properties, and one can add other here as needed. I’m using a concept with bool properties, and for every property that is true I added to the text string BoolProperties. This includes the dynamic properties as well.

  1. [EPiServerDataStore(AutomaticallyRemapStore = true, AutomaticallyCreateStore = true)]
  2. public class EPiServerPageInfo : DDS_BaseData<EPiServerPageInfo>
  3. {
  4.     public string PageName { get; set; }
  5.  
  6.     [EPiServerDataIndex]
  7.     public string PageReferenceString { get; set; }
  8.     [EPiServerDataIndex]
  9.     public string LanguageID { get; set; }
  10.     [EPiServerDataIndex]
  11.     public bool IsMasterLanguageBranch { get; set; }
  12.     public string MyCurrentPath { get; set; }
  13.     [EPiServerDataIndex]
  14.     public DateTime StartPublish { get; set; }
  15.     [EPiServerDataIndex]
  16.     public DateTime StopPublish { get; set; }
  17.     [EPiServerDataIndex]
  18.     public DateTime Changed { get; set; }
  19.     [EPiServerDataIndex]
  20.     public int PageTypeID { get; set; }
  21.     public string BoolProperties { get; set; }

With have values like this:

image

When I publish/delete or move a page I hookup on the events like this

  1. public class AttachEvents : PlugInAttribute
  2. {
  3.     public static void Start()
  4.     {
  5.         EPiServer.DataFactory.Instance.PublishedPage += new EPiServer.PageEventHandler(Instance_PublishedPage);
  6.         EPiServer.DataFactory.Instance.MovedPage += new EPiServer.PageEventHandler(Instance_MovedPage);
  7.         EPiServer.DataFactory.Instance.DeletedPage += new EPiServer.PageEventHandler(Instance_DeletedPage);
  8.     }
  9.  
  10.     static void Instance_DeletedPage(object sender, EPiServer.PageEventArgs e)
  11.     {
  12.         EPiServerPageInfo.EnsurePage(e.Page);
  13.     }
  14.     static void Instance_PublishedPage(object sender, EPiServer.PageEventArgs e)
  15.     {
  16.         EPiServerPageInfo.EnsurePage(e.Page);
  17.     }
  18.     static void Instance_MovedPage(object sender, EPiServer.PageEventArgs e)
  19.     {
  20.         EPiServerPageInfo.EnsurePage(e.Page);
  21.         if (e.TargetLink.CompareToIgnoreWorkID(PageReference.WasteBasket) || e.PageLink.CompareToIgnoreWorkID(PageReference.WasteBasket))
  22.         {
  23.             DoChildren(e.PageLink);
  24.         }
  25.     }
  26.     static void DoChildren(PageReference start)
  27.     {
  28.         foreach (var child in EPiServer.DataFactory.Instance.GetChildren(start,LanguageSelector.MasterLanguage()))
  29.         {
  30.             EPiServerPageInfo.EnsurePage(child);
  31.             DoChildren(child.PageLink);
  32.         }
  33.     }
  34. }

and update this store with the new values

  1. public static void UpdatePage(PageData page, EPiServerPageInfo row)
  2. {
  3.     row.PageName = page.PageName;
  4.     row.IsMasterLanguageBranch = page.IsMasterLanguageBranch;
  5.     row.StartPublish = page.StartPublish;
  6.     row.StopPublish = page.StopPublish;
  7.     if (page.Changed > row.Changed)
  8.         row.Changed = page.Changed;
  9.     row.PageTypeID = page.PageTypeID;
  10.     var boolItems=FindBoolProperties(page);
  11.     var b = "";
  12.     foreach (var key in boolItems.Keys)
  13.         b += " " + key + " ";
  14.     row.BoolProperties = b;
  15.     row.MyCurrentPath = DigFather(page);
  16. }

If one has special elements one would like to query against its only to add that property to the DDS class and to update the UpdatePage method.

The code is here

Jun 14, 2012

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

How to run Optimizely CMS on VS Code Dev Containers

VS Code Dev Containers is an extension that allows you to use a Docker container as a full-featured development environment. Instead of installing...

Daniel Halse | Jan 30, 2026

A day in the life of an Optimizely OMVP: Introducing Optimizely Graph Learning Centre Beta: Master GraphQL for Content Delivery

GraphQL is transforming how developers query and deliver content from Optimizely CMS. But let's be honest—there's a learning curve. Between...

Graham Carr | Jan 30, 2026