I’ve thought about building this simple extension for awhile now, and have finally gotten around to it and wanted to share it with the community. The problem I wanted to solve was simple; replicate publish & unpublish transactions which are sent from specific source publications, to a set of target publications. In this post I’ll outline what I’ve built, how it works and how you can leverage or extend it for your projects.
I was working on an implementation which had a common web publication intended for creating pages and structure groups that would be shared across a set of child web publications representing a set of local language websites. Referencing the image below – pages and structure groups were created in 400 Web Master, but there was no published website for that publication. Instead, the items were inherited in the 500 level web publications which do have local language websites available for publishing.
Publishing was actually enabled in the 400 Web Master publication – even though I mentioned there was no corresponding site for the publication. This was so that editors can publish shared items with the advanced publish settings “Also publish/unpublish in child publications” which publishes pages and structure groups to all child websites at the 500 level at once.
The problem was that most of the editors are using Experience Manager for their content updates, and even though the XPM blueprint context settings are configured so that content and pages are edited in the correct owning publications, items are only published to the site being edited (in XPM) and not all language sites. We wanted to publish the changes immediately to all of the language sites by rule, so we needed a way of mirroring publishing between two publications.
That was the problem that I ran into that I thought warranted this extension, but it’s built generically enough for any other scenarios where you would want to mirror publishing & unpublishing. It would be simple to extend this extension to only mirror publishing of items of specific schema, in an organizational element etc.
I settled on an event handler extension for the following reasons.
- Easy to setup accompanying DLL configuration file to make the extension configurable and reusable
- Easy to hook into publish transactions sent to the queue
- User experience is optimal in the sense that each mirrored transaction is represented in the queue and obvious to the user
The extension implementation itself
I built out the extension using Event Handlers via the event-system extension approach like I mentioned. The extension asynchronously hooks into the TransactionCommitted phase of a PublishOrUnPublishEventArgs event, so that we can mirror both publishing and unpublishing events. The extension is also asynchronous so that potential exceptions will not cause issues sending the original item(s) to the queue.
The logic itself for the extension is pretty straight forward:
- Check if the publication for the item being published is defined in the list of source publications in configuration.
- If the publication is in the list, get the list of targets publications defined in configuration.
- The extension also attempts to retrieve the item being published, and all resolved items, in the target publications for publish mirroring.
- Finally the extension publishes the items in the target publications to the same publishing targets as in the original publish / unpublish transaction (using the same instructions).
It’s important to understand that the publishing & unpublishing instructions used in the original publish / unpublish event are used for the mirror publish events. If the user sends an item with priority high in a source publication, the item will also be published with priority high in the target publication(s). Note that you can override some of the advanced publishing options in the configuration.
Configuring the extension
The extension ships with an accompanying configuration file which allow the extension to be configured.
The extension configuration requires that 1 or more source publications are defined, and 1 or more target publications. Publish & unpublish events which take place in the source publication will be mirrored to the target publications with the same set of publish instructions and settings.
Publish logging can also be enabled via the “PublishLoggingEnabled” property which will log all publishing transactions for debugging purposes.
And finally, some of the advanced publishing settings can be overridden in the mirrored publish / unpublish transactions via the “Force*” configurations. If set, these advanced settings will be set automatically when performing publish mirroring to the target publications.
<appSettings> <!-- Define publications by title or ID (comma-separated) where publishing mirroring should be triggered --> <add key="SourcePublications" value="tcm:0-7-1"/> <!-- Define the publications by title or ID (comma-separated) which publishing --> <add key="TargetPublications" value="400 Example Site"/> <!-- Enable logging of all publish transactions --> <add key="PublishLoggingEnabled" value="true" /> <!-- Force the advanced publish / unpublish setting to publish to child publications --> <add key="ForcePublishToChildPublications" value="false" /> <!-- Force the advanced publish setting to publish in-workflow versions --> <add key="ForcePublishWorkflowVersion" value="false" /> <!-- Force the advanced publish setting to publish minor versions --> <add key="ForcePublishMinorVersion" value="false" /> </appSettings>
Deploying the extension
If you’ve never deployed an Event-System extension, it’s super simple and only requires uploading the DLL with the event handler code, updating the Tridion configuration to add reference to your extension and then restarting the CM.
In order to install the publishing mirror you can either download the latest release directly from the GitHub release page, or download the source and compile it yourself.
In order to build & deploy the extension:
- Build the project in Visual Studio
- Copy the following files into % SDL Web Install Path %/bin/
- Open % SDL Web Install Path %/config/Tridion.ContentManager.config and add the following entry to the <extensions> list:
<add assemblyFileName="C:\Program Files (x86)\SDL Web\bin\Tridion.Events.PublishMirror.Merged.dll" />
Restart the content manager and you should be good to go. Logging will automatically be enabled assuming you copied NLog.config. You can find tridion.events.publish.mirror.log in the bin folder by default, but it is configured in the logging configuration file.