Sitecore Audit Trail – the easy way

One feature that my customers always ask me about, is the ability to know who as changed that specific page and when….

There are several reasons for this magic question, for example, the legal aspects of what you wrote on your website at a specific moment in time, could be used by customers to sue your client… a classic example is the T&C or privacy policy page that contains content provided by the legal team for an obvious reason…

In the case you are not aware and you think that customers forgot what you wrote, they may use the https://web.archive.org a kind of web history that keep track of most of the changes…

obviously, that’s a public tool, and unless you have not written the author name in the meta tag (quite unusual) you won’t know who changed that page…

Sitecore comes in your help with two OOTB approaches:

  1. Sitecore versions combined with Workflow will force your content author to create a new version of the item everytime that something got changed on an item so that you can have a more granular view of what has been changed from who… unfortunately versions do not play very well with publishing and obviously it increases the complexity and is harder to know if a specific version when exactly was published and when it was overseeded… in addition workflow are notoriously complex and make the team upset…
  2. History table, this is an OOTB feature being in place from Sitecore 6 until 9 (I think…) that keep all the changes that authors do to any item… Adam in his blog https://blog.coates.dk/2015/05/27/sitecore-history-table-how-to-control-how-long-the-entries-are-kept/ explain to you how to configure the duration period for keeping items in the history table… Note that from the history table there is no tool or UI that allow you to see what happened, but you need to go in the table on SQL and look for what you were searching for… obviously keeping history on the history table for 2-3 years, if you have a big team, it is going to affect the performance of your Sitecore instance…

However, my recommendation, in case you are on an enterprise project and workflow and versions are not an option is to log all the changes into a log file and then process the log file content in a NO SQL data repository… this approach comes with several advantages:

  1. it is scalable, you can have as many changes you want…
  2. it won’t affect performances of the CMS and it won’t pollute your DB
  3. it gives you data structured as you want… so that you can build your UI to see items changed today, or who is the content author that make more changes, review all the changes done from one user…
  4. Ability to have a free text search, eg. find out who has done any mis-spell and when on the web site…
  5. when an item was published and the content of the item
  6. it is super simple to hook into your code

the simpler way to get your logging hooked up is described in this brilliant blog: http://info.exsquared.com/ex-squared-blog/logging-changes-in-sitecore-made-by-content-authors

basically it attach to some Sitecore events, and use log4net to log on a text file, obviously you can configure it also on a different appender….

Next step, would be reading the Txt file with the audit information and upload the content on a NoSQL data structure for making it simple to search on…

Happy Logging, and end of excuses for content authors who update dodgy content 🙂

Advertisements

Sitecore Delete Published Items

Within Sitecore, the Delete button is the bigger mystery for non-Sitecore experts….

Everybody assumes that an author going in the Authoring console and Deleting an item, the item got deleted and Unpublished… but unfortunately, this is not the case….

In the case you want the item to be deleted and unpublished, you have to delete the item and have to publish the parent of the item — with sub-items —  just to remove it from a target database…

IMO Sitecore standard behavior should be to delete and unpublish, automatically but unfortunately this is not the case…

There are several possible solutions to this issue and this blog explain the possible customisation that you could do to mitigate the issue…

Introducing a new button:

https://sitecorejunkie.com/2013/08/04/delete-an-item-across-multiple-databases-in-sitecore/ 

Configuring Workflows: http://www.nonlinearcreations.com/Digital/how-we-think/articles/2016/02/Item-deletion-and-immediate-publication-in-Sitecore-8-and-8-1.aspx

My favorite option is to extend the Item Delete event to remove the item from the publishing targets as well…

This code explains how to do it…

 


 public void OnItemDeleted(object sender, EventArgs args)
 {
            Item deltedItem = Event.ExtractParameter(args, 0) as Item;
           CleanUp(deltedItem.Id.ToString());
 }
public CleanUp(string itemId)
{

  // Get all publishing targets
  var publishingTargets = Sitecore.Publishing.PublishManager.GetPublishingTargets(item.Database);

  // Loop through each target, determine the database, and publish
  foreach(var publishingTarget in publishingTargets)
  {
    // Find the target database name, move to the next publishing target if it is empty.
    var targetDatabaseName = publishingTarget["Target database"];
    if (string.IsNullOrEmpty(targetDatabaseName))
        continue;

    // Get the target database, if missing skip
    var targetDatabase = Sitecore.Configuration.Factory.GetDatabase(targetDatabaseName);
    if (targetDatabase == null)
        continue;

      DeleteItemInDatabase(targetDatabaseName,  itemId);
   }

}



private static void DeleteItemInDatabases(IEnumerable databases, string itemId)
{
   foreach(string database in databases)
            {
                DeleteItemInDatabase(database, itemId);
            }
}
 
private static void DeleteItemInDatabase(string databaseName, string itemId)
{
      Database database = Factory.GetDatabase(databaseName);
      DeleteItem(database.GetItem(itemId));
}
 
private static void DeleteItem(Item item)
{
            
            if (Settings.RecycleBinActive)
            {
                item.Recycle();
            }
            else
            {
                item.Delete();
            }
}

MVT using Publishing Targets

I have been involved in a few enterprise projects where unfortunately I cannot easily enable XDB architecture and fully leverage Sitecore capabilities for MVT testing, therefore, it comes to the idea of getting creative with what I got and find an alternative way of helping the marketing team testing the effectiveness of their new content and the new functionality that they have in mind….

I guess that it is pointless to mention, the advantages of the Testing culture and the idea behind fail quickly… however all these principles & features are covered with Sitecore MVT and in case you have XDB enabled in most of the cases I would strongly suggest you to use the built-in features…

In the specific project circumstances, I have been asked to test the effectiveness of some new “label” within the Booking funnel to see the impact on conversion….

For the Tracking, we were not using XDB and Sitecore analytics but Google Analitycs do a good job tracking Conversion and events…

For trying the different variants, I have split the sitecore change across the 4 Publishing Targets that I have for scalability reasons…  you can read more about publishing target here

My architecture requires a CDN / Proxy (Akamai in my specific case) to split the traffic across my 4 Content Delivery servers and have a publishing target different for each of the Content Delivery server…

Each Variant can be assigned to one or multiple CDs so that you can have a simple A/B testing or a more complex MVT….

With this architecture and this setup, I was able to allow the marketing team to test their content experiment and help them to find the best variation and the winning experiment even without having to configure Sitecore analytics, XDB and so on, but just leveraging the existing architecture….

The change that you would need to implement is to send via a custom dimension to GA the name of the Content Delivery server for each page view / event / transaction…

the code to track the CD, would be as simple as:

ga('set', 'cd1', 'Level 1');

obviously, this approach comes with some trade-off….  since Marketing users cannot really know which test is running and risk to override a running test doing a simple content publishing…. Also from the reporting point of view, you would need to keep track of the publishing that your content team is doing to be sure that anything else is affecting your experiment…. Also, need to remember to switch off your experiments and align all the content on the publishing targets to have a consistent web site….

 

Untitled Diagram

Sitecore Symposium 2018 recap

Since I have not attended in person Symposium 2018 I thought it may be useful write a Recap of all the exciting news that I have been reading in the last few days as a sort of quick Recap of Symposium in case you missed any…

 

  • 3000 attendees, it seems that Sitecore community has grown a lot!
  • Sitecore 9.1 is almost here
  • JSS will be part of Sitecore 9.1 and it is now part of Sitecore product so will be fully supported
  • Sitecore bought Stylelabs (DAM and PIM) read more 
  • Release cycle consolidated, two releases per year, spring and fall
  • Future of Sitecore – New UI & UX called Horizon project
  • News with Commerce:  JSS support – B2B -Product Information Management (PIM)
  • Ultimate Experience Awards read here

Personalisation & A/B Testing on standard values

I have been involved in a project where my client wanted to apply personalisation & A/B testing on the standard values rather than specific Items itself…

Initially I found the request quite odd, since the point of personalizing is to deliver a tailor made experience on each page and applying to the standard values, would mean to apply the same personalisation rule to multiple pages….

The example that my client wanted to test, was hiding the hero carousel for all the Blog pages for users who have visited the blog container landing page….

Having further conversations and thoughts, I realized that in order to Test & personalise you need to have some relevant volumes of customers & page views to understand  if the test & personalisation really work and if your website is not generating huge volumes of traffic, a workaround to boost your test & personalisation strategy is to apply personalisation rules on standard values…

The outcome of these experiments is the following one on Sitecore 9 and 8.2 update 6

Personalisation on the standard values in relationship to the presentation details, even if it is not “officially supported” works fine for my scenarios… I just added on the blog  template standard value a rule to hide the hero controller rendering if users has viewed the blogs landing page…

A/B testing on standard values does not work well, the test itself got executed but the reporting that come out is a bit funny… therefore you can potentially execute the test but the reporting would not help you to understand the winner for the test based on the engagement values & Sitecore goals… in the case you really want to achieve it, you should considering other tools for A/B testing such Google 360 or Maxymiser or write some logic withing your controller rendering to generate the test & instrument some custom reporting…

 

 

Profile cards in Sitecore 9

One of the things to know when you are going to upgrade your Sitecore instance from “8.something” to 9.0.x is that some templates may have been removed/deprecated in Sitecore 9…

An example of this issue are Profile Cards persona template…

In Sitecore 8.2 update 6 we have

image002

and in Sitecore 9 we do not have any longer the Profile Card – Persona

image001 (3)

Honestly, I do not think it is not a massive loss for marketers and I consider this simplification a good improvement…

However, in the case, you are migrating a Sitecore instance from 8.x to 9 and you have profile card persona defined, you have to remember to manually change their template to Profile Card to avoid unexpected behaviors…

Lucene Index got corrupted on Sitecore 7.5

I have recently encountered a very bizarre issue with my application pool got restarted every 15 minutes on my Content Delivery instances…. I have started to see this error, just after one deployment….

I was running the site on Sitecore 7.5 and I do use Lucene indexes…

As often happen looking into the Application log through the event viewer I found the following error:

Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: Lucene.Net.Index.MergePolicy+MergeException
Stack:
   at Lucene.Net.Index.ConcurrentMergeScheduler.HandleMergeException(System.Exception)
   at Lucene.Net.Index.ConcurrentMergeScheduler+MergeThread.Run()
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()
My first suspicious was some content author publishing when I was deploying could create some lock/race condition within the index folder?!
I tried to look into the index unsuccessfully with the index viewer and the only solution that I found, also due to the time constraint and do to the fact that site was going down every 15 minutes, it was to delete the physical folder containing the indexes, rebuild my index on the Content Authoring instance and copying the file of the index physically in the index folder…
Once I have done this operation everything run smoothly….
my take away if you are using Lucene, be always ready to re-delete and uplaod your index folder and mainly be sure that your site does not rely completely on the indexes….