Magic unpublish button
Recently I posted the question Alex de Groot asked the Sitecore community last year; "Show Sitecore how to improve..." (I paraphrased to "What's your Sitecore wishlist") to the Sitecore Australia and New Zealand users group. A few ideas flew around, one of which was a small feature request to have a magical "unpublish" button for content. Upon pushing this button the item in question would be unpublished from the live website.
So I got to thinking about how I might implement this small feature. It's actually quite straight forward. I could utilise the content editor as the author is changing attributes on the item. We even already have the attribute we want to change in question: the publishable field. I could even hook the button into one of the existing ribbon chunks on the publish tab.
Incidentally Chris Wojciech is currently doing a series of posts on extending the content editor ribbon with your own commands. Refer to these for more detail on the options you have available when tweaking the ribbon.
Firstly we need to create a new button on the publishing restrictions chunk which will perform the unpublish command for us on the item. Change to the core database and using the content editor, navigate to /sitecore/content/Applications/Content Editor/Ribbons/Chunks/Publish Restrictions. Create a new child item called "Unpublish" based on the /sitecore/templates/System/Ribbon/Large Button template. Fill in the following into the items fields:
Header: Unpublish
Icon: network/16x16/earth_delete.png
Click: item:unpublish
Tooltip: Immediatley unpublish the item
The "Click" field above contains the name of a command to execute on the server when the button is clicked. Normally you define commands in the App_Config/Commands.config file. But let's keep our custom commands separate from the Sitecore commands and define our commands in our own file. Create the App_Config/CustomCommands.config file and place the following inside the file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<command name="item:unpublish" type="MyCommands.UnpublishCommand,MyCommands.dll"/>
</configuration>
We need Sitecore to read our commands file, so open the web.config file and add the following node as a child of the /configuration/sitecore/commands:
<sc.include file="/App_Config/CustomCommands.config"/>
Now we need to implement the command. As you can see from the above configuration, our command is implemented by a .net class. Our class needs to inherit from Sitecore.Shell.Framework.Commands.Command and being that this is an abstract class, we need to implement the "Execute" method.
Inside the execute method we need to get the current item, set it's publishable flag, then perform a publish on that item to remove it from all the publishing targets.
using System.Collections.Generic;
using Sitecore;
using Sitecore.Data;
using Sitecore.Publishing;
using Sitecore.Shell.Framework.Commands;
public override void Execute(CommandContext context)
{
if (context.Items.Length > 0 && context.Items[0] != null)
{
var item = context.Items[0];
item.Editing.BeginEdit();
item.Publishing.NeverPublish = true;
item.Editing.EndEdit();
// Grab publishing targets
var targetsRoot = item.Database.GetItem(
"/sitecore/system/publishing targets");
if (targetsRoot == null)
{
Sitecore.Context.ClientPage.ClientResponse.Alert(
"Failed to find the publishing targets");
return;
}
var targets = new List<Database>();
var children = targetsRoot.GetChildren();
for (int i = 0; i < children.Count; i++)
{
var db = Sitecore.Configuration.Factory.GetDatabase(
children[i]["target database"]);
if(db != null)
targets.Add(db);
}
// Perform publish
PublishManager.PublishItem(item, targets.ToArray(),
item.Languages, false, false);
Sitecore.Context.ClientPage.ClientResponse.Alert("Item unpublished");
}
}
Compile the above code into an assembly and place that assembly in the bin folder. Now everything is ready. Make sure you're back in the master database, then using the content editor, navigate to an item, select the publish tab and click your new unpublish button. You'll receive an alert that the item has been unpublished. If you check your web databases you'll find the item is no longer there.
About to unpublish the item.
Clicking the new unpublish button.
The item has been unpublished.
And because we used the default Sitecore fields, other features such as the quick action toolbar and the alerts at the top of the fields will work to alert you that your item now has a publishing restriction applied.
A possible extension to this UI tweak would be to have the button as a toggle button. If the item is currently unpublished, then make the item publishable and publish it. Luckily Sitecore commands are not just fire and forget. They also allow feedback so in code I can make my "is item publishable" checks and set the toggle state appropriately. To make this work, I need to override the QueryState method inside my command class.
public override CommandState QueryState(CommandContext context)
{
if (context.Items.Length > 0 && context.Items[0] != null)
{
var item = context.Items[0];
if (item.Publishing.NeverPublish)
return CommandState.Down;
}
return CommandState.Enabled;
}
Easy! I should probably also in the above code check to see if the current user has write access to the item as well and set the state accordingly. And I'll need to update the Execute method code to toggle the publishable state of the item.
public override void Execute(CommandContext context)
{
if (context.Items.Length > 0 && context.Items[0] != null)
{
var item = context.Items[0];
item.Editing.BeginEdit();
item.Publishing.NeverPublish = !item.Publishing.NeverPublish;
item.Editing.EndEdit();
// Grab publishing targets
var targetsRoot = item.Database.GetItem(
"/sitecore/system/publishing targets");
if (targetsRoot == null)
{
Context.ClientPage.ClientResponse.Alert(
"Failed to find the publishing targets");
return;
}
var targets = new List<Database>();
var children = targetsRoot.GetChildren();
for (int i = 0; i < children.Count; i++)
{
var db = Sitecore.Configuration.Factory.GetDatabase(
children[i]["target database"]);
if(db != null)
targets.Add(db);
}
// Perform publish
PublishManager.PublishItem(item, targets.ToArray(),
item.Languages, false, false);
string response;
if (item.Publishing.NeverPublish)
response = "Item Unpublished";
else
response = "Item published";
Context.ClientPage.ClientResponse.Alert(response);
}
}
Unpublish button in toggle mode.
This toggle approach to publishing opens a new publishing style for Sitecore. As content authors are happy with their content, just hit the published (unpublish) toggle button. When you want to take the content offline, hit it again. For some content authors this may feel a bit more comfortable, particularly if they have used other CMSs in the past which employed a similar publishing model to this. Yes this publishing style is already available in Sitecore, but it involves clicking through a few dialogs to make it work. This tweak allows you to bypass those dialogs. And to make this new publishing model really work you'd have to tweak the publishing code to also publish any referenced and dependent items such as the items template, internal linked items and media items.
So there you go Steve, your requested tweak.
I absolutely love the state feedback on the publish/unpublish button.
But I'm thinking it would be easier to understand if the button said "Publish", and if it is glowing, than this item is already on the website. Otherwise I'm not sure what glowing "unpublish" button means
There's lots of questions in that implementation, so your design might just be the sweet spot in means of complexity. Great stuff.