Try our conversational search powered by Generative AI!

Bartosz Sekula
Feb 2, 2024
  567
(4 votes)

How to prevent publishing a page with unpublished blocks or assets

EPiServer has a very powerful validation engine which is easily pluggable with custom validation rules.

I've been asked by a colleague to write a validation rule which would prevent a page from being published if it referenced an unpublished dependency (block/asset/...).

I thought it might be useful for some of you.

We need to hook to IContentEvents.PublishingEvent. We can do that from an initializable module:

[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class PublishEventInitializationModule : IInitializableModule
{
    private DependenciesResolver dependenciesResolver;

    public void Initialize(InitializationEngine context)
    {
        //Add initialization logic, this method is called once after CMS has been initialized
        var contentEvents = ServiceLocator.Current.GetInstance<IContentEvents>();
        contentEvents.PublishingContent += contentEvents_PublishingContent;

        dependenciesResolver = ServiceLocator.Current.GetInstance<DependenciesResolver>();
    }

    void contentEvents_PublishingContent(object sender, EPiServer.ContentEventArgs e)
    {
        var dependencies = dependenciesResolver.GetUnpublishedDependencies(e.ContentLink).ToList();
        if (!dependencies.Any()) return;

        var text = dependencies.Count == 1 ? "dependency" : "dependencies";
        e.CancelAction = true;
        e.CancelReason =
            $"You can't publish because you have {dependencies.Count} unpublished {text}. {string.Join(',', dependencies.Select(x => $"{x.Name} [{x.ContentLink}] "))}";
    }

    public void Preload(string[] parameters)
    {
    }

    public void Uninitialize(InitializationEngine context)
    {
        //Add uninitialization logic
        var contentEvents = ServiceLocator.Current.GetInstance<IContentEvents>();
        contentEvents.PublishingContent -= contentEvents_PublishingContent;
    }
}

As you can see we calculate unpublished dependencies and cancel the operation if necessary.

DependencyResolver traverses the dependencies, both direct and nested, so validation will still fail if for example a page depends on an ImageBlock which has an unpublished ImageData.

Full gist is here: https://gist.github.com/barteksekula/78ff1df20df2f2449497d94c218cfdad

You can just copy paste the file to your project and it will work like this:

Feb 02, 2024

Comments

Please login to comment.
Latest blogs
Azure AI Language – Sentiment Analysis in Optimizely CMS

In the following article, I showcase how sentiment analysis, which is part of the Azure AI Language service, can be used to detect the sentiment of...

Anil Patel | May 15, 2024 | Syndicated blog

Optimizely Data Platform Visitor Groups now supports multiple instances

The module V2.0 now supports multiple Optimizely Data Platform instances, allowing personalized content based on real-time segments and profile dat...

Andrew Markham | May 15, 2024 | Syndicated blog

IP block for edit and admin in DXP

Why IP-blocking edit/admin? A hacker can try to guess user names and passwords to gain access to your site. This risk can be minimized in a couple ...

Daniel Ovaska | May 15, 2024

Do not upgrade to EPiServer.CMS.Core 12.21.4 without reading this!

Todays update of EPiServer.CMS.Core 12.21.4 alters default sort order in an unexpected way, when you are working with muligple languages and have...

Tomas Hensrud Gulla | May 14, 2024 | Syndicated blog