If you’ve spent some time with Sitecore 8.x, you’ve probably experienced the tremendously slow SPEAK driven Experience Editor (formerly known as Page Editor). This is due to multiple problems. The design of SPEAK is really chatty and cache is vital, some XHR requests are really slow and some are caused by heavy precompilations.
Kam Figy wrote a really good post about Sitecore 8 Experience Editor Performance Optimization. Read this first if you haven’t already gone through this one!
Brijesh Patel also addressed the “Suggested Tests Count” problem, where the Experience Editor ribbon blocks the rendering for a very long time just to get a list of suggested tests.
With those problems solved, I’ve found that there is a similar call for getting the number of locked items the current user have. This little digit can easily block the UI for several seconds. The figure is quite nice for authors, so let’s optimize this one.
In the Sitecore config, we can replace the ExperienceEditor.MyItems.Count
hadler in the <sitecore.experienceeditor.speak.requests>
section, with our own class. Looking at the default implementation, we see that Sitecore looks through all the items and finds items where the __lock
field contains the current user name. Though it uses Fast Query, it’s still quite slow. So I decided to go with a search implementation instead.
I’m using Solr, so this example is based on that, but it’s virtually the same if you’re using Lucene
First, we need to add the lock owner to the index. By default, the __lock
field is ignored and there is a separate computed lock
field that indicates locked items. But for this function we need to know the owner of the lock. Such field can be implemented like this:
public class IsLockedByComputedField : AbstractComputedIndexField { public override object ComputeFieldValue(IIndexable indexable) { Item obj = indexable as SitecoreIndexableItem; if (obj == null) return null; if (!obj.Locking.IsLocked()) return null; return obj.Locking.GetOwner(); } }
Then we need a replacement for the MyItemsCountRequest
class that uses the index for counting instead. This code should probably be adapted so that it fits your environment regarding getting the right search context. Here it’s pretty hard coded:
public class MyItemsCountRequest : PipelineProcessorRequest<ItemContext> { public override PipelineProcessorResponseValue ProcessRequest() { var searchContext = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext(); var myLockedItemsCount = searchContext.GetQueryable<LockedItem>() .Filter(f => f.LockedBy == Sitecore.Context.User.Name && f.LanguageName == Sitecore.Context.Language.Name && f.LatestVersion) .Take(0) .GetResults() .TotalSearchResults; return new PipelineProcessorResponseValue { Value = myLockedItemsCount }; } protected class LockedItem { [IndexField("lockedby")] internal string LockedBy { get; set; } [IndexField("_language")] internal string LanguageName { get; set; } [IndexField("_latestversion")] internal bool LatestVersion { get; set; } } }
Now we can just put this together with a config patch file, such as this:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <sitecore.experienceeditor.speak.requests> <request name="ExperienceEditor.MyItems.Count"> <patch:attribute name="type">YourNamespace.MyItemsCountRequest, YourAssembly</patch:attribute> </request> </sitecore.experienceeditor.speak.requests> <contentSearch> <indexConfigurations> <!-- change this if you're using lucene! --> <defaultSolrIndexConfiguration> <fields hint="raw:AddComputedIndexField"> <field fieldName="lockedby" returnType="string">YourNamespace.IsLockedByComputedField, YourAssembly</field> </fields> </defaultSolrIndexConfiguration> </indexConfigurations> </contentSearch> </sitecore> </configuration>
With this solution in place, the MyItem.Count
handler returns in less than 0.1 seconds. That’s in the magnitude of 100 times faster.
Now lets just hope that Sitecore starts bundling some of the XHR requests, such as “CanEdit”, “CanAddVersion”, “CanResetFields” etc, into one fewer requests. Then the Experience Editor might gain a decent performance again.
http://sitecoreblog.alexshyba.com/hidden_gem_of_sitecore_page_editor/ I knew this seemed familiar 🙂
Nice one! Thanks!
Kam my man, that was exactly what I needed. We had a lot of content items and the experience editor was waiting for 5 minutes to crawl for all the permissions and respond.
Thanks buddy!
Great post.
Sitecore now has a Support DLL for this style of fix. I’m yet to test it out, but I suspect it’s for Lucene only, and maybe a Solr one could be based off it.
https://kb.sitecore.net/en/Articles/2015/12/04/14/31/549951.aspx
Thanks,
Sean
Pingback: Speeding up Sitecore Experience Editor – Blog
do not forget using:
using (IProviderSearchContext searchContext = ContentSearchManager.GetIndex(“sitecore_master_index”).CreateSearchContext())
Pingback: Improve Sitecore Experience Editor Performance by Disabling Number of Locked Items Counter | Brian Pedersen's Sitecore and .NET Blog