21 October 2015

Workflow with auto publish related items

Workflow... Workflow... Workflow...
On most of the website we have built, we have used Data Item and Rendering Datasource quite extensively. This is great for any personalisation work and also gives flexibility for displaying components throughout the presentation... Now when setting up the workflow: Obviously we want to have the pages into the workflow but also all the Data Items that are used for the rendering sources.

Let's get the sample workflow as an exemple. This has 3 state: Draft, Awaiting for Approval, Approved. This is quite nice for a page Item so editor will edit the page then submit it for approval. Publisher will then login and approve or reject the page which in term will go published (auto published) or back to Draft if rejected.


So let's put that in our standard value of our templates:

Great we now have all of our item in the workflow...
Now we want the page to be published automatically when approved... well that is great as the sample workflow already has that:



Well Almost... since the item gets published you will also want to publish the related items. That would be best so you don't miss all your datasource items. One awesome thing is that Sitecore has it. You just need to add the related parameter as per below: 


So, now, once our item will go to the approved state it will be automatically published. Well let's try it...
Login as editor, and lock and edit a page by editing one of the component or panel (datasource item content). then save. You will see that the item gets locked but also is your datasource item:



That is great... now let's submit the page through the workflow using the experience editor, which is what our client are actually doing.


Then approve it...

and well... it did not work:

After a bit of investigation, it turns out that approving the item did not approve the datasource item... well I guess it is kind of normal as workflow are usually set on individual item... Even though the publish action on the approved state will published the related items since the Datasource items are not on the final state those are not getting published... So what can we do? what if we only get workflow on the page item? That would not work well as content are stored on the Datasource item. OK, so what if we setup 2 workflow: one for the page item: this will be the 3 steps workflow (the one above) and the second workflow will be for the datasource item. This will be a simplier one with 2 steps: Draft and Approved. on the Approved state we will put an automated publish with sub items:



Now as per the above, what we will do is create a new action on the approved state of the main workflow which will

  • Loop through the Item Renderings
  • Find the Datasources Items
  • Push them to their component workflow to the approve state so those can be published
The PublishComponents action will looks like


You can view some sample of code to loop through the renderings in the presentation on the following post:
http://sitecorepromenade.blogspot.com.au/2015_07_01_archive.html

You can see some sample of code below which can be used to push items through workflow state


        public void Process(WorkflowPipelineArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            if (args.DataItem == null)
                return;
            using (new SecurityDisabler())
            {
                var presentationService = new PresentationContext();
                if (presentationService == null)
                {
                    Logging.Logger.Warn("Could not resolve the Presentation context");
                }

                IEnumerable dataSourceItems = presentationService.GetRenderingsSettings("main", args.DataItem);

                foreach (var renderingSettingsWrapper in dataSourceItems)
                {
                    if (renderingSettingsWrapper.DataSource != null)
                    {
                        Sitecore.Data.Items.Item datasourceItem;
                        if (!Sitecore.Data.ID.IsID(renderingSettingsWrapper.DataSource))
                            continue;

                        datasourceItem = args.DataItem.Database.GetItem(new ID(renderingSettingsWrapper.DataSource));

                        if (datasourceItem == null)
                            continue;

                        if (datasourceItem[XXX.Common.Constants.ItemIds.Workflows.WorkflowState] !=
                                                        XXX.Common.Constants.ItemIds.Workflows.ComponentsWorkflow.Published)
                        {
                            PublishComponent(args, datasourceItem);
                        }
                    }
                }
            }
        }

        private void PublishComponent(WorkflowPipelineArgs args, Item pageComponent)
        {
            var workflow = pageComponent.Database.WorkflowProvider.GetWorkflow(pageComponent);
            if (workflow != null)
            {
                workflow.Execute(XXX.Common.Constants.ItemIds.Workflows.ComponentsWorkflow.SubmitAction, pageComponent,
                "auto-published due to " + args.DataItem.DisplayName +
                " was published", false, new object[] { });
            }

            if (pageComponent.HasChildren)
            {
                foreach (var childComponent in pageComponent.Children.Where(
                 x => x[XXX.Common.Constants.ItemIds.Workflows.WorkflowState] != XXX.Common.Constants.ItemIds.Workflows.ComponentsWorkflow.Published))
                {
                    PublishComponent(args, childComponent);
                }
            }
        }

Now, when you will start editing your page item, this will draft your component item. then when you will approve your page item, this will then push the component item to Approve state and published...

Hope that will help anyone.