Blog

Posts on Umbraco development as well as development and business practices

Hiding unpublished variants from the content tree

Hiding unpublished variants from the content tree

Umbraco 8 has introduced a new way of handling multilingual content: Variants. This means that a document has as many "variations" as languages available, each one able to contain content in a different language (as well as common content for all languages).

The problem with variants starts when you have multiple languages but you don't necessarily want the same site structure on every language. For example, let's take a fictional site that uses English and Spanish, and let's assume there is a set of pages in English that has no corresponding pages in Spanish, and another set in Spanish that has no corresponding pages in Englsh. Using variants, you can publish each set only for its corresponding language, but in the Umbraco content tree you end up having both sets of pages in both languages, the "unused" pages in each case being placeholders (dimmed and enclosed in parentheses). 

This is not bad when you have, let's say, 2 or 3 nodes. But what about when you have 20 or 40 nodes that are very specific to a single language? And 10 languages? You get a LOT of placeholders in your content tree and you lose focus from your real content very easily.

Let's see an example. Here's how a subtree with content primarily for the English language would look when viewing English:

Having one placeholder for something that is not addressed to an English-speaking audience (and will never be published in English, for example, local information) is tolerable.

Let's see how the same set of pages would look for the "other" language though:

Here's when the problem starts to show. Of the 6 pages that are saved, only 2 will be used in this language, while the remaining 4 will always stay unpublished since they are addressed to English-only readers. A lot of clutter making it somewhat hard to focus on the actual content for this language.

Having faced this situation more often than less with multilingual sites, we created a simple extension to the right-click menu on the home node that allows the content editor to temporarily hide unpublished variants for the language they're viewing in the content tree, making things more clear while they work under the aforementioned scenario.

We've also added this functionality on our uMazel Starter Kit 2.0 for Umbraco v8.

This option is controlled by a web.config key taking a true or false value:

<add key="HideUnpublishedVariantsFromTree" value="true" />

By enabling this functionality you start with unpublished variants hidden, but you can always toggle between hiding and showing them by right-clicking the home node and selecting the "Toggle not created variants" option.

The logic behind this is actually very silly: It just looks for dimmed names enclosed in parentheses. No server-side calls, no strange Angular stuff, just plain old DOM manipulation. (And, of course, possible to break in some future Umbraco update, but very simple to maintain).

So how was this done?

We needed two ways to interact with unpublished variants on the tree.

The first one was simply toggling between showing and hiding unpublished variants that were on the tree at a given time.

The second was checking whether the setting was active and hiding every unpublished variant from that point onward (meaning we had to watch the DOM part of the tree for changes) 

For the second way, we had to add a right-click option to the tree nodes. We chose to do so on the Home node only, although it's pretty easy to implement for any node. We handled the MenuRendering event for the back office content tree so that we could have our custom option and have JS code executed when it was clicked:

Our JS code was added in a custom plugin that was created in the "HideNodesFromTree" folder under App_Plugins.(Well, you can use any name there).

Here are the code files for that. Arrive.js is an open source plugin that can be found at https://github.com/uzairfarooq/arrive

Finally, here's the API controller that hider.js calls:

So what happens is that when the back office is loaded, hider.js takes action and calls the API controller to find out whether the web.config setting is enabled or not. (Can't find out via JS!).

If it's found to be true, then hider.js uses arrive.js (a very handy JS plugin with which you can track changes to the DOM)  to track whether items with a specific CSS class (the class the Umbraco back office gives to unpublished stuff) are created, checks if they are enclosed in parentheses, and if so, it hides them.

The menu option, on the other hand works in a much simpler way: When clicked, it calls the HideShowTreeNodes() function found in toggle.js which does the same kind of thing without implicating server-side code, since it interacts only with nodes that are on the tree at that time. It just looks for stuff with this specific CSS class that are enclosed in parentheses and toggles them between visible and not visible status. 

I know this is a bit far from perfect, but hey, it's just an interesting way to handle the unpublished variant clutter. Hope it helps!

Happy coding!