Monday, 16 May 2016

Submitting a page to workflow with associated datasources

I've recently inherited a project at a client where all content - both pages and datasource items - have been assigned a workflow, and the pages are comprised of numerous components with their own datasources.  The workflow assigned to the content is simple, but the issue the client was facing was that when they were using Experience Editor, they would go into a page and lock it for editing, then change some text - but the text was in the datasource of the component that had been included on the page! This meant when they clicked 'submit' to send their changes for approval, it would submit their page item, but not the datasource item that they had changed.  As authors who were new to Sitecore (some of whom were new to CMSs altogether) this was very confusing to them.

To be honest I was a little surprised that Sitecore doesn't automatically submit datasource and other content items changed through Experience Editor with the page item, and even more surprised that I couldn't find anything online on how others had tackled the issue.

Fortunately Sitecore makes this relatively painless to sort out through workflow actions.  Create a new /sitecore/templates/System/Workflow/Action item under your workflow's Submit command item.  In the "Type string" field enter the name of your custom class (I called mine SubmitRelated).  Our class will find all the datasource items included  in presentation details of the current item (page) being submitted, and if these items are locked by the same user it will assume they should be submitted as well, so will "submit" (change the workflow state) and unlock them.
Getting the datasources in the presentation details of an item can be found in a few blog posts, but the easiest I've found is Brent Svac's post.
public class SubmitRelated
{
  private const string AwaitingApproval = "{46DA5376-10DC-4B66-B464-AFDAA29DE84F}";

  /// <summary>
  /// Finds all related content locked by the current user and moves to approval state.
  /// </summary>
  /// <param name="args">Workflow arguments</param>
  public void Process(WorkflowPipelineArgs args)
  {
    Item workflowItem = args.DataItem;

    foreach (Item datasource in workflowItem.GetDataSourceItems().Where(i => i.Locking.IsLocked()))
    {
      string lockOwnerName = datasource.Locking.GetOwner();
      if (!string.IsNullOrEmpty(lockOwnerName) 
        && Security.Accounts.User.FromName(lockOwnerName, false) == Context.User)
      {
        using (new EditContext(datasource))
        {
          datasource[FieldIDs.WorkflowState] = AwaitingApproval;
          datasource.Locking.Unlock();
        }
      }
    }
  }
}

Edit 6 Sep 2016: It looks like Sitecore 8.2 brings some excellent functionality to the Experience Editor, including (amongst other things) a whole bunch of additions around managing related datasources! Excellent work Sitecore devs.

1 comment: