Screenshot of the Neos document tree with some blog posts marked as draft

Marking draft content in the Neos CMS backend

Categories:

When I write new blog posts for this website, I create them in a "draft" workspace. Over the years I sadly also created quite a bunch of posts, which never saw the light of the day, as I was never able to finish them. The problem is that I cannot differentiate which blog posts have never been published, while I'm in this "draft" workspace. To verify that, I would need to open the backend twice to compare or flip back and forth between workspaces. Both are not fun. So I present a better alternative that I came up with some days ago and which you can see the article image above.

The Eel helper

The first step is to create a new Eel helper in your (site) package with the following code. Make sure to adjust the namespace in line 5 to match yours.

<?php

declare(strict_types=1);

namespace My\Site\Eel;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Eel\ProtectedContextAwareInterface;
use Neos\Neos\Domain\Service\ContentContextFactory;

class NodeHelper implements ProtectedContextAwareInterface
{
    public function __construct(protected ContentContextFactory $contextFactory)
    {
    }

    /**
     * Returns true if the given node exists (even if hidden or removed) in its base workspace,
     * or its workspace has no base workspace.
     */
    public function existsInBaseWorkspace(NodeInterface $node): bool
    {
        $workspace = $node->getWorkspace();
        // If the node is in a personal workspace, we need to check its base workspace instead
        if ($workspace->isPersonalWorkspace()) {
            $workspace = $workspace->getBaseWorkspace();
        }
        $baseWorkspace = $workspace->getBaseWorkspace();
        if (!$baseWorkspace) {
            return true;
        }
        $baseContext = $this->contextFactory->create([
            'workspaceName' => $baseWorkspace->getName(),
            'dimensions' => $node->getContext()->getDimensions(),
            'targetDimensions' => $node->getContext()->getTargetDimensions(),
            'invisibleContentShown' => true,
            'removedContentShown' => true,
            'inaccessibleContentShown' => true,
        ]);
        return $baseContext->getNodeByIdentifier($node->getIdentifier()) !== null;
    }

    public function allowsCallOfMethod($methodName): bool
    {
        return true;
    }
}

The helper accepts a node as parameter and checks whether it is in a sub-workspace and its base workspace. For my case that would be the check if it exists in the currently selected "draft" workspace and the "live" workspace. If that is the case or I'm currently looking at a node that is in the live workspace, the helper returns true.

Register the new helper

To make the helper available to be used in a nodetype you have to register it like this in a Settings.yaml file:
Neos:
  ContentRepository:
    labelGenerator:
      eel:
        defaultContext:
          'My.Site.Node': 'My\Site\Eel\NodeHelper'
Once again, make sure to adjust the namespace to yours.

Adjust the nodetype labels

And now we override the label of the basic document nodetype mixin (or any nodetype you want to mark this way) to use this helper to conditionally add a prefix to the nodes in the document tree:

Neos.Neos:Document:
  label: "${Neos.Node.labelForNode(node).properties('title').prefix(Shel.Site.Node.existsInBaseWorkspace(node) ? '' : '(DRAFT) ')}"

This change can be added into a new yaml file located in your package under NodeTypes/Override/Document.yaml for example.

When you now reload the document tree in your Neos backend while you are in a workspace that contains documents that don't exist in the "live" workspace yet, you should see the the prefix "(DRAFT)" in the label of those documents.

Using unicode

You can also get more creative by using unicode characters:

Example of using unicode characters in the labels

Summary

This post shows a compact and well manageable way to highlight nodes with specific conditions in the page tree. Hopefully we will find good ways to make this easier for future Neos versions, f.e. by allowing multiple icons for a node or custom color variations.

Please get in touch if this helped you to find other or even better ways to mark nodes and I gladly link or mention your input.