Protecting critical content and improving auditing with Delete plug-ins

Protecting critical content and improving auditing with Delete plug-ins

For Tridion Docs customers, it is necessary to protect critical content and ensure transparency when deletions occur. This is where notifications, governance rules, and audit capabilities become essential.

To reduce the risk of accidental deletions, a notification mechanism can be implemented for the delete process using Tridion Docs integration points. As an option for implementation, before deletion, stakeholders (such as content owners or subject matter experts) can be notified via email or system alerts with a list of proposed deletions. This allows them to review and confirm whether the content is truly obsolete or still in use. Notifications can also show that someone checked the content before it was deleted.

In regulated industries or organizations with strict content governance policies, certain content must be retained or protected based on legal, compliance, or business rules. For example, topics tagged with custom metadata such as RetentionPolicy: Permanent or LegalHold: True should be excluded from deletion workflows. Integrating governance rules into the delete plugin ensures that protected content is never removed, even if it appears unused. This safeguards the organization from accidental loss of critical or legally required documentation.

Even having notifications and restriction rules in place sometimes is not enough. Being able to audit the delete action is important in enterprise content management. With the Delete plugin, every delete action can be logged with detailed metadata, including:

  • Who initiated the deletion
  • When the deletion occurred
  • Which objects were deleted
  • What metadata was associated with the object at the time of deletion

Such an audit trail not only supports internal accountability but also helps with troubleshooting issues that may arise post-deletion.

Delete Plugins

With the new Delete plug-ins mechanism, customers can set additional restrictions for the delete action by adding their additional rulesets. As well as that, they can store information about the delete action to build an audit log.

Starting from Tridion Docs 15.1, Delete plug-ins are supported on Content Objects (Document objects like topics, maps, libraries, images, and others), Publication Outputs, Publications and Publication versions, and Baselines.

To support Delete plug-ins configuration there is a new configuration entry in the XML Settings area.

Tridion Docs consumes this feature. An out-of-the-box implementation for the Delete plug-in is used for the Metrics feature to synchronize data with Metrics storage. When an object is removed from Tridion Docs Content Manager a delete event is used to synchronize data with the Metrics storage to reflect the current repository state.

Hierarchical logical-version-language can look like a cascade of deletes

Tridion Docs is using a logical-version-language domain model that, by its nature, has a cascade deletion effect that cannot be avoided and should be considered when Delete plug-ins are engineered.

You can have an upward cascade effect and a downward cascade effect. 

Upward cascade effect

For the upward cascade effect in case, if you delete the last lover-level object, it will trigger the deletion of an object one level up.

Downward cascade effect

For the downward cascade effect deletion of an upper-level object will trigger deletion of its lower-level objects.

How to tune when the Delete plug-in triggers

To have control over both cascade effects for Delete plug-ins you have two conditions to specify IshLevel and OriginalLevel.

IshLevel corresponds to the level on which the plugin is expected to be executed.

OriginalLevel represents the level from which the event action is triggered.

Correct configuration for them depends on the logic that you implement. Conditions allow you to limit the amount of delete events and make your system behave efficiently and according to your defined business logic.

A couple of examples to understand the conditions for the Delete plug-ins.

  • In case Ishlevel is set to language level and OriginalLevel is not set at all – the plugin will be executed whenever the language level gets deleted. It can be a result of direct language deletion or a part of a cascade effect when an upper-level (version or logical) object is deleted
  • In case Ishlevel is set to language and OriginalLevel set to logical then the plugin is executed only as an indirect result of language object deletion (starting either from logical or from version levels)
  • If both Ishlevel and OriginalLevel are set to language level, then the plugin is executed when the language level is deleted directly

Both parameters can be set for the plugin configuration using the ishcondition attribute.

For example, the configuration for the plug-in that is executed when the language object itself is deleted looks like below.

<plugin name="RaiseLanguageSyncDeleteEvent" handler="OnObjectDeleteSendEvent" ishcondition="ISHLevel='lng' and OriginalLevel='lng'">
  <description>Raises an event if the language object is created or modified</description>
  <workingset>
    <ishfields>
      <ishfield name="FTITLE" level="logical" />
      <ishfield name="VERSION" level="version" />
      <ishfield name="DOC-LANGUAGE" level="lng" />
      <ishfield name="FRESOLUTION" level="lng" />
      <ishfield name="FSTATUS" level="lng"/>
    </ishfields>
  </workingset>
  <initialize>
    <parameters>      
      <parameter name="EventType">SYNCHRONIZELANGUAGEOBJECT</parameter>
      <parameter name="RequestedMetadata">
        <ishfields>
          <ishfield name="FTITLE" level="logical" />
          <ishfield name="VERSION" level="version" />
          <ishfield name="DOC-LANGUAGE" level="lng" />
          <ishfield name="FRESOLUTION" level="lng" />
          <ishfield name="FSTATUS" level="lng"/>
        </ishfields>
      </parameter>
            <parameter name="WaitTime">00:05:00</parameter>
    </parameters>
  </initialize>
</plugin>

To learn more about Delete plug-ins configuration please visit our documentation.

Example Plug-in to log delete metadata in a file system log file

As an example of the Delete plug-in, you can use the attached solution CustomDeletePlugin.zip.

The LogDeleteEvent plugin raises events for topics, library topics, maps, libraries, images, and templates including deletion of their versions and languages. Events are triggered also for Publications and Publication versions, Publication Outputs, and Baselines.

Minimal configuration that should be defined via Organize Space using the XML Settings>Delete plug-ins.

  <plugin name = " LogDeleteEvent" handler="CustomDeletePlugin">
    <description>Send an event when the object is being deleted.</description>
        <initialize>
            <parameters>
                <parameter name="LogDirectoryPath">C:\InfoShare\DataSQL2022\Logs\</parameter>
            </parameters>
        </initialize>
</plugin>

As you can see in the example configuration ISHLevel and OriginalLevel parameters are not defined. This means that all delete events on all three levels (logical, version, and language) will be processed.

Information about the delete action is logged into the file that is passed using the LogDirectoryPath parameter.

An example of the LogDeleteEvent plug-in execution for the topic that has one version and one language you can see below.

{
"timestamp": "2025-04-02T12:17:47.550Z",
  "event": "Delete",
  "data": {
    "userName": "admin",
    "action": "Delete",
    "logicalId": "GUID-D9613655-A6D8-4C75-BAC1-D5A709507F48",
    "ishVersionRef": "24148754",
    "ishLngRef": "24148755",
	"ishType": " ISHModule "
  }
}
{
  "timestamp": "2025-04-02T12:17:47.576Z",
  "event": "Delete",
  "data": {
    "userName": "admin",
    "action": "Delete",
    "logicalId": "GUID-D9613655-A6D8-4C75-BAC1-D5A709507F48",
    "ishVersionRef": "24148754",
    "ishLngRef": "",
	"ishType": " ISHModule "
  }
}
{
  "timestamp": "2025-04-02T12:17:47.608Z",
  "event": "Delete",
  "data": {
    "userName": "admin",
    "action": "Delete",
    "logicalId": "GUID-D9613655-A6D8-4C75-BAC1-D5A709507F48",
    "ishVersionRef": "",
    "ishLngRef": "",
	"ishType": " ISHModule"
  }
}

CustomDeletePlugin.zip
  • Hey Andriy, excellent post, and you have inspired me to create a What if...? blog post on this idea. I'll send you a link when it's published. In the meantime enjoy some other What if...? moments here: https://www.linkedin.com/feed/update/urn:li:activity:7338248784239284224 

  • Nice post, Andriy! 

    I like the idea of allowing deletion requests by users which can then be acted on by other users (or perhaps automated). I've seen a CMS setup (in Tridion Sites) where deletions were not allowed by regular users, so even accidentally copy-and-paste errors or test content needed a manual request to an admin to remove the content.

    A real business requirement would be to be able to research and possibly restore any content that has been made public before. This often comes up with as part of a regulatory requirement to retain content that has potentially been seen by the public for a certain number of years. So being able to programmatically "catch" and handle a deletion request is a more nuanced and user-friendly approach to meeting the actual legal requirement.

    And good reminder on the dependencies between publication, version, and language. Dependencies make deletions tricky. Slight smile