Search code examples
content-management-systemwagtailwagtail-admin

Support multi-site approval based workflow on wagtail


Objective

We would like to setup multi-site wagtail with approval chain.

Develop -> QA -> Release -> Production

Description

  • A develop / content editor goes to the wagtail admin and creates the content. Once done, sends the request for approval to move to QA site.
  • QA moderator reviews the content on develop site. If approved, the content gets moved to QA site. The content carries over to next stage approval (release).

Same process ahead for next sites in approval chain.

Questions

Is it possible to setup a publish chain with approval policy in wagtail? I tried to research a bit but could only find "workflow" and "workflow tasks". Do I need to custom code a workflow task to be able to achieve this?


Solution

  • This should be possible but you will need to consider what you really want to do in regards to the 'move' step, do you want to actually move the Page instance to a new site in a new tree or copy the current (and its history) and move that copy Page OR make a copy to put in place of the Page that was moved.

    Nonetheless, the documentation on how to add a new Task type is the best place to start, it walks you through custom Task types.

    In the solution below however, I thought it would be simplest to create a new model that behaves exactly like GroupApprovalTask (the default task included, used for moderation) but add a field that links it to the Site model.

    This way, in the admin UI the admin users can now create as many PublishSiteTask as you want, one for each Site (QA/Dev/Prod etc) and then each of those could be linked to different user groups. It is important to differentiate between the database model (a task type with some fields) and the instances (a task created in the UI) and the actual task instances that are created against each page revision (not page) as the workflow steps progress.

    Code Example

    models.py

    from django.db import models, transaction
    
    from wagtail.core.models import GroupApprovalTask, Page, Site
    
    # ... other imports
    
    class PublishSiteTask(GroupApprovalTask):
        site = models.OneToOneField(Site, on_delete=models.CASCADE)
    
        admin_form_fields = ['site'] + GroupApprovalTask.admin_form_fields
    
        @transaction.atomic
        def on_action(self, task_state, user, action_name, **kwargs):
            """Performs an action on a task state determined by the ``action_name`` string passed"""
            if action_name == 'approve':
                # get the page that this action is referring to via the task_state.page_revision
                page = task_state.page_revision.as_page_object()
    
                # find the new parent target at this task's site
                # how this is done depends on the site/page structure
                new_parent_target = self.site.root_page 
    
                # move the page to a new location
                # note: this will actually move it from its current tree, you may want to make a copy first
                page.move(new_parent_target)
    
            # be sure to preserve any existing task behaviour
            super().on_action(task_state, user, action_name, **kwargs)
    
    
    
    • Task class definition
    • GroupApprovalTask class definition
    • You may want to do some pre-work in the code to check that the page can actually move to the different Site, each Page has a method can_move_to that could help.
    • The move method referenced above is part of the Wagtail code but the full docs for that method can be found in the Treebeard API docs which Wagtail uses to manage the tree structure.