You can use dynamic content packages to periodically export the data that's been created or modified in the last X days in the source instance and then import that content package into the target instance. That way you can keep the content in sync without performing full database copy. This post focuses on creating such packages and on one of the challenges you are likely to face in this process.
Dynamic packages
In one of my previous posts (Sitecore Content Packages) I have explained two ways of adding items to content package specifications. The first one is adding items statically, where you just list the items individually and Sitecore Package Designer tool will always pick up those exact items when you generate the content package. The second way is adding the items dynamically where you set a starting point (the search root item) and optional filters. When you generate a content package using such package specification Package Designer will search the sub-tree that descends from the set search root item and apply all the filters you might have set, thus dynamically creating a list of items to be exported every time you start the export.
Using dynamic packages for content sync
By using the Creation Date and Modification Date filters you can set up dynamic package specifications to export items that have been created or modified in the past X days. Such content packages can be used to keep two different Sitecore instances in sync, or in content migration process to additionally migrate some items that might have changed since you did a full migration.
Here’s the example of two content package specifications that are used to export Templates, Media Library and Content items created or modified within the past 5 days.
Content package specification for created items:
Content package specification for modified items:
As you can see, I have split the export in two content packages – one for created items, one for modified items. If both “created” and “modified” sources were in the same package then the items for which both Created Date and Updated Date are inside the set period of time would be included in the same content package twice and on import that would create two identical versions on that item. Because of that it’s best to keep these two content packages separate.
Once you generate these two content packages from source instance you can import them into target instance. Because some of the exported items already exist in target instance the import process will ask you what to do with them (Overwrite, Merge, Skip). In the case where you want to sync data between two instances Merge-Merge is probably the best option. All the options are very well explained in this blog post by Martijn van der Put.
Issue with copied and duplicated items
The dynamic export of items that have been created or modified in the past X days relies on the Created Date and Updated Date on each of the items:
Based on these values Sitecore will determine if a particular item needs to be included in our export package.
While working with dynamic content packages I have discovered an issue with Created Date and Updated Date not always being updated by Sitecore. The problematic functionalities are:
- Copy Item
- Duplicate Item
The items that are newly created by copying or duplicating have the same Statistics (Created Date, Created By, Updated Date, Updated By, Revision) as their originals. The same happens with their children items that were copied or duplicated together with them. I have seen this issue in Sitecore 6.6 and in Sitecore 8.0 and 8.2. In Sitecore 6.6 this issue is also present when renaming the item – the Statistics also don’t change - but that part has been fixed in Sitecore 8. Cloning doesn’t have that issue neither on Sitecore 6 nor on Sitecore 8.
This creates a problem for our dynamic export – because Created and Updated dates are still in the past (copied from the original items) Sitecore doesn’t recognize the newly created items as new and doesn’t include them in our export of items created or modified in the last 5 days. These new items are simply not included in generated ZIP file. In big Sitecore instances, where content authors are constantly creating new content (and, of course, using very handy features like Copy and Duplicate) this can present a significant problem that prevents us from reliably syncing content between two Sitecore instances.
Is this a Sitecore bug? Looks like it is, at least to me. I’ll try creating a ticket with Sitecore support about this and see what they have to say.
The workaround
In the meantime, I’ve come up with a custom event handler that solves this problem. Here’s the class with the code:
using System;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Events;
using Sitecore.Security.Accounts;
namespace Coria.Events
{
public class ItemCopiedEventHandler
{
public void OnItemCopied(object sender, EventArgs args)
{
Item item = Event.ExtractParameter(args, 1) as Item;
Error.AssertNotNull((object)item, "No item in parameters");
using (new UserSwitcher(Context.User))
{
// we have to update revision information (Created Date, Created By,
// Update Date, Updated By and Revision number) because standard Sitecore
// functionality does not do that when copying or duplicating items
UpdateRevision(item);
}
}
private void UpdateRevision(Item item)
{
item.Editing.BeginEdit();
// clearing Created will make UpdateRevision method also update Created Date and Created By fields
item.Fields[FieldIDs.Created].Value = string.Empty;
item.Statistics.UpdateRevision();
item.Editing.EndEdit();
// do this recursively for all children (because item:copied event fires only
// for the top item being copied or duplicated)
foreach (Item child in item.Children)
{
UpdateRevision(child);
}
}
}
}
And here’s the config file that puts our code into action (put this somewhere in your App_Config\Include folder structure):
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<events>
<event name="item:copied">
<handler type="Coria.Events.ItemCopiedEventHandler, Coria" method="OnItemCopied"/>
</event>
</events>
</sitecore>
</configuration>
As you can see, this custom handler reacts on item:copied event that fires at the end of Copy and Duplicate processes. It uses Sitecore’s standard Item.Statistics.UpdateRevision method to update all the fields in item’s Statistics section.
I hope you’ll find this useful!