Changing workflow state of Sitecore items programmatically

27 December 2013
Marek Musielak
Frink_Cognifide_2016_HeaderImages_0117

Sitecore Workflows provide a great mechanism of creating, maintaining and reviewing content. Editors can use built-in applications like Workbox or execute workflow commands from the Sitecore Content Editor or Page Editor. However in some cases developers need to change the workflow state of the item from the code without accessing UI. This blog post explains how this can be achieved in 3 scenarios:
  • 1. Change workflow state of an item only.
  • 2. Change workflow state of an item and execute new state actions.
  • 3. Execute workflow command which fires it's actions, updates workflow state and fires new state actions.

Case 1: We need to change workflow state but we don't want to execute any workflow commands or actions.

This is the simplest scenario and we're not going to focus on it. If the only thing that needs to be changed is the workflow state and we're not interested in any commands or actions, the only thing we need to do is to update the __Workflow State field of the given item:
public static WorkflowResult ChangeWorkflowState(Item item, ID workflowStateId)
{
    using (new EditContext(item))
    {
        item[FieldIDs.WorkflowState] = workflowStateId.ToString();
    }

    return new WorkflowResult(true, "OK", workflowStateId);
}

public static WorkflowResult ChangeWorkflowState(Item item, string workflowStateName)
{
    IWorkflow workflow = item.Database.WorkflowProvider.GetWorkflow(item);

    if (workflow == null)
    {
        return new WorkflowResult(false, "No workflow assigned to item");
    }

    WorkflowState newState = workflow.GetStates()
        .FirstOrDefault(state => state.DisplayName == workflowStateName);

    if (newState == null)
    {
        return new WorkflowResult(false, "Cannot find workflow state " + workflowStateName);
    }

    return ChangeWorkflowState(item, ID.Parse(newState.StateID));
}

Case 2: We want to change the workflow state and execute all the workflow actions for the new state.

There are 2 types of workflow actions in Sitecore:
  • 1. If a workflow action definition item is created under workflow state item, the action is executed when an item enters the particular workflow state.
  • 2. If a workflow action node is created under a command item, the action is triggered when the command is executed.
More information in about workflow actions can be found in Sitecore CMS Workflow Reference. In some scenarios we may want to change state of an item like in the Case 1 and additionally execute all the workflow state actions defined under the new workflow state item after state is changed. In this scenario we need to start the Sitecore pipeline for the new workflow state after it is assigned to the item and increase the WorkflowCounters if we want to be consistent with Sitecore approach:
public static WorkflowResult ChangeStateAndExecuteActions(Item item, ID workflowStateId)
{
    using (new EditContext(item))
    {
        item[FieldIDs.WorkflowState] = workflowStateId.ToString();
    }

    Item stateItem = item.Database.GetItem(workflowStateId);

    if (stateItem.HasChildren)
    {
        WorkflowPipelineArgs workflowPipelineArgs = new WorkflowPipelineArgs(item, null, null);

        Pipeline pipeline = Pipeline.Start(stateItem, workflowPipelineArgs);
        if (pipeline != null)
        {
            WorkflowCounters.ActionsExecuted.IncrementBy(pipeline.Processors.Count);
        }
    }

    return new WorkflowResult(true, "OK", workflowStateId);
}

Case 3: Executing workflow command to change the workflow state.

If we want to mimic the Sitecore UI behavior and execute the command which will change the workflow state, we need to use WorkflowProvider to get an instance of the workflow assigned to the given item and call Execute method with a chosen command ID. This will fire all the actions which are defined under the command item node, change the state of the item and fire all the auto-actions defined below the new state item node:
public static WorkflowResult ExecuteCommand(Item item, string commandName, string comment)
{
    IWorkflow workflow = item.Database.WorkflowProvider.GetWorkflow(item);

    if (workflow == null)
    {
        return new WorkflowResult(false, "No workflow assigned to item");
    }

    WorkflowCommand command = workflow.GetCommands(item[FieldIDs.WorkflowState])
        .FirstOrDefault(c => c.DisplayName == commandName);

    if (command == null)
    {
        return new WorkflowResult(false, "Workflow command not found");
    }

    return workflow.Execute(command.CommandID, item, comment, false, new object[0]);
}
One thing you need to remember while changing the workflow stateof items in Sitecore is that Sitecore will check access rights and won't allow to execute commands or actions if current user doesn't have access to them. If you need to execute them anyway you can always use SecurityDisabler.

If you have any questions or comments, leave a note below or check out my other
Sitecore blog posts.