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();
            }
}