Passing Params to the ServicesConfigurator for DI in Sitecore

pexels-malte-luk-1397751

We are using the IServicesConfigurator interface to configure our services from code and registering it in the <services> section in the Sitecore config. However I had a situation where I wanted to pass some configuration values (to do with a custom cache) to the ServicesConfigurator in order to do something different.

This was my ServicesConfigurator class before I made any changes:

public class MvcControllerServicesConfigurator : IServicesConfigurator
{
  public void Configure(IServiceCollection serviceCollection)
  {
   serviceCollection.AddMvcControllers("*.Feature.*");
   serviceCollection.AddClassesWithServiceAttribute("*.Feature.*");
   serviceCollection.AddClassesWithServiceAttribute("*.Foundation.*");

   //get my param values here
  }
}

This was the config for the pipeline:

       

Normally in Sitecore pipelines we can just set Params in the config of the Pipeline (e.g <useMyCustomCache>true</useMyCustomCache>) and grab them within the pipeline class like so:


public class MvcControllerServicesConfigurator : IServicesConfigurator
{
 public string UseMyCustomCache { get; private set; }
 public void Configure(IServiceCollection serviceCollection)
 {
  ...

  if(bool.Parse(UseMyCustomCache)){
    //do something here
  }
  ...

 However the this doesn’t work and causes an error like so:

[LockRecursionException: A read lock may not be acquired with the write lock held in this mode.] System.Threading.ReaderWriterLockSlim.TryEnterReadLockCore(TimeoutTracker timeout) …

Ok so How do I make this work?

It seems the issue is that Sitecore’s configuration Factory is not available at this point in the initialisation of Sitecore (as it’s also injected with DI). Therefore you can’t do this and you also can’t read any settings using it either (e.g: Settings.GetSetting(“useMyCustomCache”)). So I stumbled across this really useful post with a solution to this using the ConfigReader instead, and it works perfectly. This is my updated ServicesConfigurator code:  

public class MvcControllerServicesConfigurator : IServicesConfigurator
{

 public void Configure(IServiceCollection serviceCollection)
 {
  serviceCollection.AddMvcControllers("*.Feature.*");
  serviceCollection.AddClassesWithServiceAttribute("*.Feature.*");
  serviceCollection.AddClassesWithServiceAttribute("*.Foundation.*");
  
  var useMyCustomCacheNode = Sitecore.Configuration.ConfigReader.GetConfiguration().SelectSingleNode("sitecore/services/configurator/param[@desc='useMyCustomCache']");

 var useMyCustomCache = useMyCustomCacheNode != null ? useMyCustomCacheNode.InnerText : "false";


  if(bool.Parse(useMyCustomCache)){
    //do something here
  }
  ...

This is the final config which follows the same format as a number of Sitecore Pipelines which uses the param format:

Hopefully this useful to anyone else who needs to do this.

As usual there were some really helpful blog posts I found related to this:

https://smartsitecore.com/en/additional-configuration-in-sitecore-pipeline-process/

https://briancaos.wordpress.com/2010/12/10/parameters-in-sitecore-pipelines/

http://sitecore-community.github.io/docs/documentation/Sitecore%20Fundamentals/Sitecore%20Configuration%20Factory/#config_factory

https://kamsar.net/index.php/2016/08/Dependency-Injection-in-Sitecore-8-2/

https://trnktms.com/2021/02/16/getting-sitecore-configuration-from-service-configurator/

Sitecore Technology MPV Award 2023

mvp-banner-2023-narrow

This week I was privileged to be presented with the Sitecore Technology MVP award for the 6th year in a Row .

There are only 241 MVPs Worldwide and just 8 Technology MVPs in the UK (137 Worldwide), all of which have been awarded for:

“demonstrating outstanding engagement and support for the global Sitecore community”.

It’s a great Community to be involved in and I’ve enjoyed organising and presenting at the Manchester Sitecore User Group over the past year, meeting other Sitecorian’s and sharing my knowledge on this Blog, YouTube, Twitter, SSE and Slack.

You can see all the 2023 MVPs in the Directory here: https://mvp.sitecore.com/Directory

Why become an MVP?

There are many benefits to being an MVP, here are some of them:

  • Being viewed as a global Sitecore expert & community leader
  • Access to early product release / resources / product teams and kick-off webinars
  • Access to MVP discussion forums
  • Regional MVP meetings
  • MVP Summit after Symposium (insight to product / company strategy)
  • Discounts for SUGCON & Symposium

You can read more about the MVP programme here.

Thinking about becoming an MVP?

This is a really useful SSE post on the kind of activities you need to be involved in if you would like to become an Sitecore MVP and this Blog Post is a great resource.
You can also reach out to previous and existing MVPs on Twitter/Slack etc and I’m sure they will help guide you or answer any questions you have.

There is also an mentor programme which may be something to look at if you feel you need further guidance and help on your Journey.

Congrats to all 2023 MVPs and thanks to Sitecore and the MVP Team for their support and assistance over this year. Here’s to another year of Sitecore’ing ?.

Using ChatGPT to write SPE

chatgpt-spe

Catchy title huh? it Rhymes and everything.
Anyway, my Twitter timeline has been non stop about ChatGPT this, and ChatGPT that for the past few weeks – and I’ve seen it doing some pretty cool stuff.

I also keep hearing how it’s going to make Software Developers redundant, so it got me thinking about something I do every few days as a Sitecore Developer:

“Can ChatGPT write some decent Sitecore PowerShell Extensions scripts?”


TLDR:
Yes it can. Not terrible anyway. Read on to find out more.

Wait, what is ChatGPT?

Chances are that you already know what it is else you probably wouldn’t be reading this, but just in case – ChatGPT is an impressive AI Chatbot created by OpenAI (backed by Microsoft & others) that can take inputs and provide some very comprehensive and usually pretty accurate answers.

The Tests – How did ChatGPT do?

So I fired up my browser, created an account on https://chat.openai.com/ and after waiting for it to become less busy for a while, I got started with asking for some SPE scripts:

chatgpt-busy

ChatGPT Test 1 – Create me an Sitecore item

I thought I’d begin with something fairly simple – creating an item, it seemed like a nice place to start. It’s often something I need to script (perhaps usually to create a bunch of items). This is what came back:

spe-create-item-chatgpt

My Score = 6/10

Other than the fact it seems to have tried to import SIF at the top of the script!?, Initially I was quite impressed as it looked pretty close to what I would write myself.
However when I tried to run the script in the SPE ISE (using the Sample Item Template Id) it was clear that it had some of the parameters incorrect. It had miss-understood how to use the -ItemType and had also tried to pass -Template in as a parameter and there is no such thing so it wasn’t quite right but not a bad effort. After correcting these issues this is the final working script:

 

ChatGPT Test 2 – Unlock all Items for a User

This time I went for something a little more tricky, unlocking items is something I’ve quite often need to do in the past – where users have gone on Holiday and left an lot of items locked for example. Here is what it came up with: spe-unlock-items-chatgpt

My Score = 9/10

Again it tried to import SIF at the top of the script, but other than that it actually created some working code. Amazingly similar to Marek’s SSE answer:

spe-unlock-sse

I was able to just remove the SIF imports at the top and run it and it seemed to work. It took a while (as I have  a lot of test content locally) and there is no logging to show what happened but it didn’t error and did complete. Here is the working script:

ChatGPT Test 3 – Remove all old versions of an Item

This time I tried something I’ve had to do recently and took quite some time to write as was fairly complex. I wanted a script to remove all but the 10 most recent versions of an item but to always keep item versions that are 3 months old or less as well. Here is the script it came up with:

spe-delete-item-versions-chatgpt

My Score = 3/10

These more complex scenarios and perhaps where ChatGPT starts to fall down a bit. It has tried to build two list (one of old versions and one of recent versions) and then remove the versions from the item and then add back the recent and old versions in memory.
This won’t work as it’s not updating the item itself and it’s not possible to set the Versions property on the item like this (instead $itemVersion| Remove-ItemVersion should be used). The logic is also not quite right here for sorting and filtering the versions. If you compare my script linked above there is quite a lot missing and wrong here due to the nuances with Sitecore item versions.

ChatGPT test 4 – Create me a package with a UI

A final test is also a task I’ve implemented recently. The scenario was a bit more complex than this but I thought I’d see how it got on with something similar:

spe-create-package-chatgpt

My Score = 2/10

The script created here isn’t great to be honest. It didn’t quite get the properties correct for the Treelist UI. It has created the Package ok but the Add-ItemToPackage method does not exist, it should instead be using New-ItemSource.
Similarly it seems to have made up a function called Save-Package which should instead be Export-Package. Lastly it’s tried to offer me an link to the package to download it, which won’t work as it needs to either be an link to the default packages folder or use the Download-File option instead to present it to the user to download.
Interestingly when I tried to re-word my instructions to see if I could get it to use the Download-File method it actually tried to add items in a different (but still incorrect) way and tried to use the inbuild .NET Framework methods to download the zip to my browser which won’t work in the context of SPE ISE:

spe-create-package2-chatgpt

Conclusion

So am I worried I’ll be surplus to requirements anytime soon? In short – not currently no. The average of my (not so scientific test) was 5/10.

I think the nuances of a complex platform like Sitecore are hard for an AI powered tool to fully understand to an extent where it can automate code to an good-enough standard currently.

However, I think it could be a great starting point for an SPE script, especially for stubbing out the basics of something. It could also be really useful if Google or SSE fails you and you just can’t find any example code for a task you are working on. It is also very impressive that it can interpret what I’m asking for so well and write some half decent code.

I am not exactly sure how it works, but I’m guessing it’s injesting information from Sitecore Blogs, SSE, Sitecore Documentation Sites and reading the Dlls/Code online, as well as taking learning input from trainers and end-users.

If so then over time it’s going to become better and better and writing code and eventually I might be down the Job Centre wondering what happened.
If it manages to absorb Mark Kassidy’s brain then we will all be in Trouble…

XM Cloud Demystified

xm-cloud-banner

I had heard a lot about XM Cloud over the past year or so at SUGCON and from Symposium as well as from the Sitecore Community, however I realised I didn’t really know that much about it still and wasn’t clear on what was included.

Given that XM Cloud was officially released for general availability at Symposium it was about time I learned about if properly and answered some of the questions I had.

So I dived into the XM Cloud documentation and watched a lot of Videos and setup the local XM Cloud instance to learn more about it. I then decided I’d try and speak at the next Sitecore user group in Manchester on XM Cloud to share what I learned. Nothing like a deadline to force you to learn about something properly huh? :-).

You can see the Slides and Video of my presentation ‘XM Cloud Demystified’ below.

Update: You can see an more recent talk I did on XM Cloud at the Columbus Sitecore User Group back in March which is clearer, newer and more in-depth too: https://www.youtube.com/watch?v=8yw0kNrh-f4

In my presentation I talk about:

  • What XM Cloud is
  • The benefits of XM Cloud
  • What is included and what is not
  • How it compares to Sitecore XP
  • Where it fits in with the new SaaS products Sitecore has acquired and developed
  • The different development and deployment approaches
  • Show how XM Cloud looks and Demo my local Instance

What’s Included?

In my research one thing I couldn’t find was a list (or diagram) of everything that is included in XM Cloud. So I put together a list on one of my slides (see my Slides below), however I really wanted to create a diagram of this. I didn’t get chance to before my talk but I’ve now created one which you can see below.
I’m sure it’s not as fancy as Sitecore would have done but it’s pretty clear I think.

Update: after some feedback from Pieter Brinkman on Linked In I’ve updated the diagram a little. Sitecore search is not included, it is instead available as an add-on. XM Cloud Forms Builder is also a Roadmap feature. I’ve also added SPE and Automatic updates to the diagram.

xm-cloud-whats-included-v2

Slides of Presentation

Here are my slides from the SUG (see the Video of my presentation below).

Video of Presentation

Here is the Video of my Talk. Click the video below to jump to my presentation.

Update: You can see an more recent talk I did on XM Cloud at the Columbus Sitecore User Group back in March which is clearer, newer and more in-depth too: https://www.youtube.com/watch?v=8yw0kNrh-f4

I leaned a lot from my research and hopefully this is useful for people looking to get an clear over-view of XM Cloud. If you want to know more the developer docs have lots of information.

If there is anything I’ve missed or got wrong then please let me know on Twitter or in the comments so I can correct it as I’m still learning about XM Cloud and things are changing all the time.

While your here check out the rest of the SUG as well as we had some other great talks too.

Adding Items to a Custom Sitecore Seach Index using SiteCron

old-books

Over the years working with Sitecore I’ve had to create custom indexes and add items to them for most clients I’ve worked for. I’ve generally written a Search Crawler and Search Indexer to handle this but it’s always seemed like a lot of code to manage just to add a few items to an index and temperamental to control the indexing frequency accurately. I’ve also had many issues with Indexes being out of Sync in the past due to Sitecore Events not firing on CD instances etc.

I’ve tried various approaches to simplifying this in the past but unfortunately never got this working. However this came up again on a recent project and I was successful this time – so decided I’d share my approach and code.
Note in this example I’m using Solr but in Theory this same code should work with Azure Search also.

In simple terms the approach is to:

1) Create a Custom Index – to store my content (in this case Blogs)
2) Create a Search Indexing Service – which will retrieve the Items and add them to the Custom index
3) Create an SiteCron Indexing Job – which will call my Indexing Service to Index the Items on a regular basis
4) Create a Search Results Page – which will display the search results from the Index

Benefits of this approach

  • Less Code to write and manage
  • Can control how often the indexing runs very accurately (using SiteCron) and this persists across App Service / IIS Restarts.
  • Easy to test and maintain

1) Creating a Custom Solr Index

I’m not going to go into this process too much as it’s documented well elsewhere but essentially you need to copy on of the out of the box solr folders, rename it and also update the core.properties file. For this example I’ve created and index called sc93_blogs_index:

custom-index-folder

Configuration

You will also need to add 2 configuration files for the custom Index like so to define the index name, strategy (of manual) and configure the fields to include. Amend these as required for your use-case:

Index Config:
Index Fields Config:

 

2) Search Indexing Service

The next step is to create our Search Indexing Service. This will get the blog items and add them to the index. This could easily be pulling Info from an datatabase, API or File instead if needed.  I’ve called mine BlogPostSearchService:

 public class BlogPostSearchService : ISearchService
 {
  ...
 }

I also added an interface with  two methods:

public interface ISearchService
{
   int IndexContent();

   BlogPostSearchResultsModel GetResults(BlogPostSearchResultsModel blogPostSearchResultsModel, string searchTerm, int resultsPerPage, int currentPage);

}

Index Content Method

The IndexContent() Method is like so. Note this code is not optimal if you have more than a few hundred items within a folder, you may wish to re-structure your items differently:
 

Get Content Method

The GetContent() Method is as follows:

Supporting Models / Classes

There are various supporting models and classes used in the above code. Below are the key ones.

BlogPostSearchResult

My Blog Posts just have two additional properties so this is pretty simple:
public class BlogPostSearchResult: SearchResultItem
{
    [DataMember]
    [IndexField("Title")]
    public string Title { get; internal set; }

    [DataMember]
    [IndexField("Description")]
    public string Description { get; internal set; }
}

BlogPostSearchResultsModel

This Model is used to hold my search results and some other properties about the search results for use in the View:

public class BlogPostSearchResultsModel
{
    public string SearchTerm { get; set; }
    public IPagedList<BlogPostSearchResult> SearchResults { get; set; }
    public int TotalNumberOfResults { get; set; }
    public int NoOfResults { get; set; }
    public int Page { get; set; }
}

Settings

You will notice there are some settings used in the code such as for the Blog Post Items Path. Add a Sitecore patch file for these and configure them as needed.

Paged List

I’m using an Nuget Package for PagedList, this is a good one if you want to use one too: https://github.com/dncuug/X.PagedList

3) SiteCron Indexing  Job

The next step is to create our SiteCron Job which will be responsible for indexing the content. This calls the IndexContent() method on the service. Obviously this needs to match your SiteCron Job name above.
See my post here about logging to the last run log etc if you’d like to do that too.

  This is then setup in SiteCron to run like so, schedule it to run as needed: sitecron-job 

4) Search Results Page

The last step is to display the Search Results. Create a page in Sitecore using whatever template you use. Then Create an Controller Rendering and View in Sitecore, reference the Controller below and add the rendering to the page.

Controller

The Controller looks like so:

View

The View, this is a simplified version:

The Result

So once you’ve done all the above you should end up with something like the following:

search-results-page-blogs

 

Hopefully this helps someone else who need to implement a custom search and illustrates an alternative approach that could work for them.

Fixing Solr Azure App Service Core Locking Issues

solr-core-locking-error

We have had intermittent issues with our Sitecore Solr instance in Production which runs in an Azure App Service. Every so often it crashes and we see Core Initialisation errors like so:

sitecore_web_index: org.apache.solr.common.SolrException:org.apache.solr.common.SolrException: Index dir 'D:\home\site\wwwroot\server\solr\sitecore_web_index\data\index/' of core 'sitecore_web_index' is already locked. 
The most likely cause is another Solr server (or another solr core in this server) also configured to use this directory; 
other possible causes may be specific to lockType: native

Doing some research into this it seems that the consensus is that Azure App Services shouldn’t really be used for Solr:  https://sitecore.stackexchange.com/questions/23466/solr-cores-locking-v-9-0-2

However I couldn’t actually find any official Sitecore documentation that says that Azure App Services are not supported / recommended for Solr and there are plenty of blog posts out there about setting up Solr for Sitecore in Azure App Services.

We could have switched it to an VM but we’d rather not do that as it’s easier to manage and maintain an Azure App Service than an VM and Microsoft will also handle all the security patches too etc.

So I opened a support ticket with Sitecore to confirm if App Services can be used for Solr and they suggested that I try the following:

1. Make sure the Azure Web App is not scaled out (instance count should be set to 1).
2. Make sure the environment variable WEBSITE_DISABLE_OVERLAPPED_RECYCLING is set to 1

We already have our App Service scaled to just one instance but when checking the configuration settings we didn’t have the WEBSITE_DISABLE_OVERLAPPED_RECYCLING setting set.
So we added this config and set the value to 1:

solr-recycling-config
Setting this to 1 stops new instances of the app being started before the current instance is shut down – which can cause locking.

Since making this change we’ve not had any issues with it intermittently locking.

Update: I still had issues with cores locking occasionally and started on a solution for it using PowerShell in a Runbook a while ago and I have now completed this and shared it here: https://www.flux-digital.com/blog/auto-re-starting-solr-indexes-get-locked-azure-app-service/

Hope this helps someone else who’s having this issue too.

Creating Preview / Draft Sites in SXA using SPE

sorcerers-stone-banner

A few weeks ago I was tasked with providing the ability for content editors to be able to have a preview (or draft) site for SXA sites when using the CM Url. The requirement was to be able to view ‘Draft’ content/versions of pages (without publishing them) for stakeholders to be able to preview them before they are published to the CD instance.

In an Traditional Sitecore setup this is pretty easy, you would just edit the site definition config in the Sitecore config with a patch file to change the database used to Master when on the CM.
For SXA this is a bit trickier as the Site definitions are dynamically built by SXAs site manager when Sitecore starts up (or the SXA Site Manager is ran again in Sitecore).

However after reading around it seems it was possible to achieve what I needed to do. I had to duplicate the existing Site Grouping definition item and change the database that it uses to Master. See an example below:

draft-site-def

I also changed the environment to ‘Draft’ and added the following Patch file on the CM only, this tells the CM that the current environment is ‘Draft’ and to use Site Definition items with that environment setting:

 <sitecore>
    <settings>
       <!-- Environment name used by cm-->
       <setting name="XA.Foundation.Multisite.Environment" value="Draft" />
    </settings>
 </sitecore>

The last thing I did is change the name of the Site Grouping definition item and the title to include the word ‘Draft’. This was to make it clearer to content editors and stakeholders that they are editing/viewing ‘Draft’ content.

This results in each SXA site having two site Site Grouping definition items; the original (pointed at the Web DB) which the CD instance will use and the new Preview/Draft site that the CM instance uses:

draft-site-structure

Automating Creating of Draft Sites with SPE

As I needed to create Draft sites for quite a few sites I wrote an SPE script to do this for me:

 

Deleting Draft Sites

Should you need to remove your draft Sites (e.g during local testing) then I wrote a script for that too:

Site Ordering

One thing I discovered is that the order of the Sites in the SXA site manager matters. SXA will return the first one it matches based on Environment and the order defined here:
/sitecore/system/Settings/Foundation/Experience Accelerator/Multisite/Management/Sites

You therefore need to ensure the Draft site is above the original site grouping in the list. You can re-order these in the SXA Site manager using the up and down arrows but I had some issues with this not taking affect so instead I moved the draft sites up the list in the field they are stored in instead. As I had a lot of sites to do this for I actually ended up writing an SPE script to move all the draft sites to the top of the list:

 

Right-Click ‘Create Draft Site’

The above scripts were really useful to get the draft sites setup for the existing sites but I also needed a way to quickly add draft sites for new SXA sites in future. I decided an nice way or doing that would be using an SPE context menu script.

right-click-create-draft-site

Here is the script, make sure you place it here: e.g: /sitecore/system/Modules/PowerShell/Script Library/{YOUR SCRIPT LIBRARY}/Content Editor/Context Menu:

Get CM Url Function:

Move Draft Site Function:

Experience Editor Notification

draft-exp-editor-message

Again in order to make it clearer to content editors and stakeholders that they are editing/viewing ‘Draft’ content I decided an Experience Editor Notification would be useful. So again I turned to SPE to do this. I’m not sure if that many people know you can do this with SPE but it’s a really simple way to it with no C# code or config required:

Note that if you are using SPE 5 on Sitecore 9.02 or 9.01 then you will likely find there is a bug in the SPE config and you need to patch it like so to move the getPageEditorNotifications to the correct section of the config:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
 <sitecore>
 <pipelines>
 <group name="ExperienceEditor" groupName="ExperienceEditor">
 <pipelines>
 <!--patch to add SPE 5.0 PageEditorNotifications in correct config group-->
 <getPageEditorNotifications>
 <processor type="Cognifide.PowerShell.VersionSpecific.Integrations.Pipelines.PageEditorNotificationScript, Cognifide.PowerShell.VersionSpecific"/>
 </getPageEditorNotifications>
 </pipelines>
 </group>
 </pipelines>
 </sitecore>
</configuration>

The end result of this work is that I now had Draft site functionality setup for all required sites, quick ways to add new draft sites as needed and it is clear to content editors that the draft site content is in use on the CM.

Dedicated Preview Instance considerations

Obviously for some scenarios you might have wanted to have a dedicated Preview/Draft instance with an specific url such as www.preview-mysite.com and publish to an ‘Preview’ database publication target. The config for the environment and hostname would then be used here instead. However for our purposes using the CM url is fine as the access is restricted and cuts down on costs of an additional instance in Azure.

Useful Links

As usual there were some really useful blog posts which helped point me in the right direction with this and figure out what I needed to do:

https://ggullentops.blogspot.com/2019/04/publishing-target-in-sitecore-sxa.html

https://getfishtank.ca/blog/setting-up-multiple-hosts-sitecore-sxa-site

https://blog.senktas.net/2019/10/20/sitecore-powershell-extensions-integration-with-experience-editor/

 

Hopefully others will find this information and the scripts I’ve written for setting up Preview sites in SXA useful in future.

p.s – if you wondering why the Harry Potter image; well apparently it took J. K. Rowling 13 attempts to finally get someone to publish the Philosopher’s Stone so it nearly remained in Draft and never published!

Removing Unneeded Sitecore Versions with SPE

versions-header

It’s been a while since I had to look how best to manage Sitecore versions, but after seeing some performance issues related to lots of versions for some items on the CM this week It was time to revisit removing unneeded Sitecore versions.

Research

Amusingly my search turned up an SSE post with an answer from myself from about 5 years ago: https://sitecore.stackexchange.com/questions/507/limiting-version-numbers-copying-old-versions-to-archive-for-easy-access/525

Screenshot 2022-05-24 231555

Further Googling shows not much seems to have changed in that time. Some modules are however no longer supported or are compatible with Sitecore 9. I did find some links that gave me a few ideas though.

Our requirements were to find any items with more than 10 versions and then remove any versions other than the most recent ten unless an version is the currently published version or the version has been updated on the past 3 months. The idea behind this is that we wanted to remove only versions that were old and not updated recently but leave versions that are recent even if there are a lot of them for actively edited pieces of content.

The Script

Given the various modules available for managing versions are out of date and we only needed to this on an adhoc basis I decided to turn to trusty SPE to write a report which initially reported on items with 10 or more versions and then listed how many items to keep and how many to remove.

I was aware that Out of the box SPE has an report for item versions, so I used this as a basis for mine but added the check for if the version is the published version or has been edited within the past 3 months.

I then expanded on this to generate detailed reports of all the versions to keep and versions to remove.

Lastly added some options within the report to allow the item versions to be removed after the report has run an also if to archive the items to disk and/or the archive database table.

report-versions

The result of this is that I could just run this in report mode first for analysis and then with the ‘Archive Versions & Generate Reports’ option selected to also remove the un-needed items.

Here is the script:

If you wish to change the number of months to a longer or shorter period you can update this variable value: $months = -3

When running the report with ‘Archive Versions & Generate Reports’ option selected it will ask you to confirm before removing items to be on the safe side:

confirm-remove

Note that in newer versions of SPE the Remove-ItemVersion command archives items by default. However in the version we were using (5.1) this doesn’t happen so I added code to archive to the database before removing the item version.

Results

After the report has run an summary of results is shown and they can be downloaded in excel or csv format etc.

report-results

2 Other Spreadsheets are also automatically created and downloaded:

1. Versions to Keep – all the versions that will be kept for each item (these should correspond with the report above)

2. Versions to Remove – all the versions that should be removed for each item (these should correspond with the report above)

Running this in our production environment (after extensive testing) resulted in over 6,000 un-needed item versions being removed and over 7,000 being kept. This took around 40 minutes to run in total and the logs show info on what is happening.

Nearly halving our item versions means we should see some performance benefits and also it tidies up our database.

This also provides the added benefit of 3 reports we can reference if needed and the ability to restore versions from the archive if we need to in future for whatever reason. We plan to empty the archive in 6 months or so when we are sure these versions are not needed.

Hopefully someone else will find these scripts useful for managing item versions in Sitecore too. Feel free to edit it for your own use-case, please test carefully in a non-production environment though before running it.

Useful Links

There were some useful links I found regarding managing versions, including an SitecoreVersionPruner SPE script that I found after I’d written mine which looks really good:

https://github.com/danielrolfe/SitecoreVersionPruner

https://thesitecorist.net/2019/05/11/removing-old-versions-using-sitecore-scheduled-tasks/

https://briancaos.wordpress.com/2019/03/01/sitecore-delete-old-item-versions/

https://www.logicalfeed.com/posts/1195/sitecore-powershell-script-to-remove-all-language-versions-except-one

https://robearlam.com/blog/extending-sitecore-revolver-to-remove-old-versions

SUGCON 2022 Thoughts and Takeaways

SUGCON-2022-header

It’s been 3 years Since the last ‘In-Person’ SUGCON in London 2019, so I was really looking forward to going to Budapest to learn some new Sitecore things and catch up with Sitecore Developers and friends from across the world. I’ve been to Budapest for a weekend once before and It’s a beautiful city.

After a long flight with a change at Amsterdam I arrived at the Conference centre in Budapest pretty late but immediately bumped into a bunch of people I know from the Sitecore Community. After a drink in the bar it was time to hit the sack ready for the first day of SUGCON.

Day 1.

Steve Tzikakis – Opening Keynote

There was a notable excitement in the room as Tamas opened up SUGCON to much applause welcomed everyone and introduced Steve Tzikakis to the stage.

Steve seemed genuinely happy to be at SUGCON and have the opportunity to talk to the Sitecore Developer Community. He hit us with some Stats about the platform. Apparently there are 2,200 Sitecorians and the last two years have bought about the biggest changes in Sitecore’s 21 year history.

IMG_0525

Things have accelerated forwards in Digital during the pandemic and Sitecore has taken advantage of this by investing huge amounts of Money on the platform and employees. The have doubled their spend on R&D and doubled the number of employees across the organisation, 60% of staff have only been at Sitecore a year or less!. Innovation is key for Sitecore to gain an competitive edge and to claim the number 1 spot so they have spent 22% of their revenue on R&D.

IMG_0530

Steve shared an impressive Side of well known brands that now user Sitecore and talked about how Sitecore want to grow the platform to 3,000 customers but without increasing their service offering. Instead they want to do this by enabling partners to deliver better and more quickly on a Modern Mar-tech stack that has flexible, headless Commerce, CDP and Content integrated together with the best interface for the task at hand, this all sounds good to me.

Anyone that has not been living in a Jam Jar for the past two years will have noticed that Sitecore spent a whole lot of money procuring a number of platforms over the last 24 months or so. These are: Content Hub (Stylelabs), Boxever, MooSend, Four41 and Reflektion.

IMG_0533

These products all bring a number of functions to Sitecore that it is currently missing, whilst also having some overlap with what XP already offers. So I was interested to see what’s happened with these acquisitions and what the plans are for them going forwards. Next up was Dave ‘O Flanagan to talk more in-depth about some of this.

Dave ‘O Flanagan – Re-Imagining the DXP

IMG_0537

Dave opened by explaining how his Son caught COVID over lock-down and went from an average FIFA player to an Expert after isolating in his room with his PlayStation for 10 days and playing it non stop. This demonstrates that things have accelerated extremely fast during the pandemic and Sitecore has had to adapt to this change quickly.

IMG_0547

Dave discussed how Sitecore are invested in cloud first and that they have shifted their position to not try and sell customers the whole Sitecore stack but just the parts they really need by focusing on speed, flexibility, relevance and agility.

The following slide regarding where Sitecore is today was interesting:
IMG_0551

And here is the future Roadmap for Sitecore for 2022:
IMG_0553One element of this is the XM Cloud offering, this will be a headless architecture which is cloud-ready, with site layout and page management, analytics, personalisation and testing, executed at the edge.
IMG_0567

IMG_0574

Next, Content Hub Headless was introduced, this looks really interesting. Essentially an light-weight headless CMS built on top of Content Hub.

IMG_0568

Dave then handed over to Andy Cohen to show us more about XM Cloud.

Andy Cohen – XM Cloud

Andy opened up by Telling us what XM Cloud is:

IMG_0577

And also what is isn’t:
IMG_0581

Next Andy introduced XM Cloud deploy and attempted an live deployment.

IMG_0583

Andy had a few technical issues (as is often the way with complex live demos) but he managed to deploy Sitecore using Cloud deploy in Just over 5 minutes! That’s pretty impressive from an empty environment in the cloud.

IMG_0590

Akshay Sura & Kamruz Jaman- What it means to be a Sitecore Architect in the Composable DXP world

Next up for me was fellow Sitecore MVP’s Akshay and Kamrus sharing all the knowledge they have learned on working with Composable DXPs.

IMG_0594

These guys have spent a lot of time working with Composable DXPs with Sitecore and other vendors over the past few years and they really have a lot of useful knowledge to share.IMG_0596

One of the key messages was that a different approach is required with Composable.

IMG_0599

A lot of Solutions already involve a many integrations, however they are likely not as decoupled as they should be.
IMG_0600

A key thing that was mentioned it is not a one-size fits all approach and there are advantages as well as disadvantages.
IMG_0601

IMG_0602(1)

Here is an overview of a typical Composable DXP Solution.

IMG_0605

The approach should be based around the architecture and business strategy and not just the technical solution.

IMG_0606

It was also interesting to see the different in development cycle for Typical Sitecover Development vs Composable.

IMG_0607

As you can see the phases can be overlapped much more to allow Sites to be delivered much faster and therefore new features to be built sooner.

IMG_0610

One thing to get your head around is that a lot of Composable systems don’t have visual editor for the web or any channel so this is one of the trade-offs and things to adjust to.

IMG_0611

The session finished with some slides that helped answer some questions that most .Net developers must have asked themselves in the past few years. It’s good to see we are not redundant :-).

4-com-dev

This session was very useful for anyone who has not stepped into the Composable world yet, I really appreciated the honestly too.

Thomas Desmond – Flexible Static: Static Site Personalization at the Edge

This session looked interesting and after the previous talk I thought it would be good to learn more about what can be done with Edge Functions and the like.

IMG_0619

One of the trade-offs of Static Sites is obviously the loss of Personalisation due to it.. err ..being static. Rehydration allows for personalisation to be done on the edge.

IMG_0621

Some examples of data available at the edge:
IMG_0624

Sitecore Personalize can be used to get user data and display a personalised version of the page to the user.
IMG_0630

The middleware functions do this look pretty powerful. I’m going to add this to my list of things to experiment with over the next few months.IMG_0627

Martin Miles – The mastery of Sitecore Upgrades

I know Martin from the Sitecore Community and when I heard he was doing a talk on upgrades I knew it would be one I’d be attending. Upgrades might not be the most exciting of subjects but if you’ve done a few Sitecore Upgrade like me your always looking for any tips and tools for your arsenal to make them easier.

IMG_0633

Martin shared a ton of really useful information in his talk. I’m going to pick out some of the key ones only here as there are far too many useful ones to share and Martin Blogged about it the other day and shared his full slides.

Two different approaches to upgrades:
IMG_0636

Stages of an upgrade and estimating it:
IMG_0638

The need for being able to roll back attempted upgrade steps bit by bit:
IMG_0643

Tip 1:
IMG_0656

Tip 2:

IMG_0658

This was one of the most time consuming issues I had with my last Sitecore upgrade :-(.
IMG_0664

Those DLLs that have been removed changed will need re-writing/updating:
IMG_0683

I blogged about Items as resources at the end of last year but if you upgrade to 10.1 or newer then the upgrade is simplified as the default Sitecore databases are empty now.
IMG_0686

End Of Day 1

And with that Day One at the conference came to an end. It was time for Dinner, the Awards ceremony, Quiz and Drinks.

Later I went into Budapest with some friends from the Sitecore community to  explore and have a few drinks. If you’ve not been to Budapest before the Ruin Bars were pretty cool.

IMG_0701

Scooters back from the pub were kind of entertaining.

IMG_0714

Day 2

After breakfast I headed down to the first session of the day that I wanted to catch.

Himadri Chakrabarti – Frontend First Architecture for Headless CMS

IMG_0721

Himadri’s session was an interesting lightning talk on how to create a decoupled architecture using front-end.

IMG_0723

I’d not really thought about IOC from the perspective of front-end so it was cool to see how this works with Next.js and typescript and how TSyringe can be used to integrate with a Headless CMS and switch between them.

IMG_0725

Useful links from this session:
IMG_0726

Ronald van der Plas – Content Hub Scripting as a Professional

My next Lightning talk was on Content Hub Scripting. I’ve not really done much with Content hub yet so I was interested in finding out more.

IMG_0729

We were shown how the built-in C# scripting capability works and it’s limitations but also how to work-around these with the CLI.

IMG_0736
The Content Hub CLI support a number of operations and can be run from the command line.
IMG_0739
Core Commands
IMG_0740

Environment Setup. This allows developers to sync scripts between Content Hub and their local machine and to run unit tests too.

IMG_0743

Corey Smith – Stop Worrying and Love the HttpClient

The last lightning Talk was by fellow MVP Corey. He’d hit this issue with the HttpClient causing issues with socket exceptions on nearly every client project he’s worked on and wanted to share his learnings.

IMG_0745

If you’ve ever done this on a Sitecore 8.2 – 9u2 project then your basically doing it wrong:

IMG_0753

This is how you should be doing it. The important bit is the Connection Lease Timeout.
IMG_0754

This is how you would use the Client Accessor:

IMG_0750

For Site 9.1 and beyond there is a slightly different approach which you should use.
IMG_0751

IMG_0752

 

Rodrigo Peplau – CDP & Personalize for Sitecore XP fanatics

After lunch I decided to go to Rodrigo’s session on CDP & Personalize as I’ve read a lot about Boxever / Sitecore CDP but I’ve not used it yet.

IMG_0757

Rodrigo did a great job of drawing comparisons with Site XP during his talk, calling out similar features we are comfortable with.
IMG_0759

IMG_0760

Concepts such as Personalisation and MV Testing and their counterpart in CDP were explained with examples.

IMG_0761

An overview of how to integrate with CDP and Personalise was given.
IMG_0764

The Boxever JavaScript looked pretty straight forward to integrate and powerful too.

IMG_0767

Sending events to Sitecore CDP using the JavaScript works as follows:

IMG_0768

Contacts are Guests in CDP
IMG_0773

Decision Models are used to create business logic in the CDP
IMG_0774

This was a nice comparison of Variants in CDP vs Variations in XP
IMG_0785

Audiences can be targeted with Personalize in a number of different ways
IMG_0789

All in all this was a really insightful session and helped me better understand how CDP works and what you can do with it.

Marc Ramer – Sitecore Discover – real-time intelligence for product search and merchandising

After a break I attended a session on Sitecore’s Search Platform acquisition (Reflektion). I’ve heard very little about this since it was purchased so was intrigued to learn more.

IMG_0804

We saw a live demo of Sitecore Discover in action on a website selling products.

IMG_0806

We were then shown the API details

IMG_0812

The Customer Engagement Console also seems to have a lot of powerful options

IMG_0814

Here are some analytics showing in the Console.IMG_0815

There are also a lot of Implementation options to pick from.

 

IMG_0821

We were also given some info on the Discover SDK

IMG_0822

Jake Hookom and Roger Connolly – Detailed Product Roadmap – Closing keynote

It was now time for the final session where we found out what was on the Roadmap for Sitecore from Jake and Roger.

IMG_0827

There was a lot of cool information (and surprises) in this session so I’ll share some of the key slides on XM Cloud, Sitecore Pages, Sitecore Components, Composable from any datasource!, Webhooks and the main Roadmap too.

IMG_0830

Sitecore Manager Looks interesting

IMG_0834

Sitecore pages will be in XM Cloud and looks impressive.

IMG_0835

IMG_0836

XM Cloud Personalisation

IMG_0838

Personalisation on the Edge in XM Cloud

IMG_0842

Sitecore Components in XM Cloud

IMG_0845

This slide was a Game changer, Sitecore allowing data sources from Competitor CMS platforms such as Contentful and Kentico. Who’d have though this would every happen a few years ago.

IMG_0847

Awesome Roadmap around APIs

IMG_0849

Event Webhooks allow extensibility in an Composable world.

IMG_0850

IMG_0851

Here is the detailed 2022 Roadmap (Borrowed from Twitter as my photo has poor contrast):

0-sitecore-roadmap

Closing

And with that the first In-Person SUGCON in 3 years was over and it was time to head to the airport for my flight home.
It was a very enjoyable SUGCON where I learn a lot and got to catch-up with a lot of friends and people I know in the Sitecore Community. Well done to all the organisers on putting together such a awesome event and to all the speakers for the great talks. There is certainly a lot to digest and mull over here, but the future looks bright and (dare I say) exciting for Sitecore developers in 2022.

IMG_0860

 

Removing Unneeded Tags from RTE fields with Sitecore PowerShell Extensions

bacon-575334_1280

This week I had an issue where some items imported from another system into Sitecore had invalid HTML in some of their RTE fields. These tags were breaking the SXA page content component that was being used.

I needed to a quick way to remove these tags without having to re-import the content. As usual SPE came to the rescue again and I was able to correct 100s of items in seconds.

The script has a function which takes an item and field name as a parameter:

Strip-InvalidTags -item $item -fieldName "Details"

I’m getting a number of profile items and calling this function in a loop. The function uses HTMLAgilityPack to look for ‘Script’ tag nodes (but can easily be modified to pick up different tags or multiple tags). If the script finds the tags is strips them and then saves the modified html back to the field.

Here is the script that I created:

Hopefully it’s useful for others who might need to do this.

Thanks again to the community for some useful ideas: https://sitecore.stackexchange.com/questions/20795/using-powershell-extensions-to-remove-empty-p-tags-from-all-rich-text-fields/20802