Try our conversational search powered by Generative AI!

Bartosz Sekula
Feb 2, 2024
  551
(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
Why C# Developers Should Embrace Node.js

Explore why C# developers should embrace Node.js especially with Optimizely's SaaS CMS on the horizon. Understand the shift towards agile web...

Andy Blyth | May 2, 2024 | Syndicated blog

Is Optimizely CMS PaaS the Preferred Choice?

As always, it depends. With it's comprehensive and proven support for complex business needs across various deployment scenarios, it fits very well...

Andy Blyth | May 2, 2024 | Syndicated blog

Adding market segment for Customized Commerce 14

Since v.14 of commerce, the old solution  for adding market segment to the url is not working anymore due to techinal changes of .NET Core. There i...

Oskar Zetterberg | May 2, 2024

Blazor components in Optimizely CMS admin/edit interface

Lab: Integrating Blazor Components into Various Aspects of Optimizely CMS admin/edit interface

Ove Lartelius | May 2, 2024 | Syndicated blog