Plone Content Type With Custom Workflow Via Generic Setup
This tutorial has a very long title, let's take a look at it to understand what this is all about.
- Plone Content Type. Ok, so we want a content type. If you want to know more about content types you might be interested in reading the tutorial on My First Minimal Plone Content Type.
- Via Generic Setup. You might have read a little tutorial called Plone Generic Setup First Contact and gotten a first idea of it. Generic Setup is included in this tutorial for only reason: there is no other way. (Either I don't know enough about Generic Setup or the approach of using XML/ZCML and so on does not fit my brain. I've said it before and I'll say it again: I just wanna do python.)
- Custom Workflow: Ok this seems to be something new. And indeed it is - this is the new stuff this tutorial is about.
I wanted to learn more about home made Workflows so this tutorial describes one way of making a content type with its own workflow. There are at least two ways of writing your own Workflow: one way where you have to write XML from scratch - that sucks if you ask me. The other way (that modifies an existing workflow in ZMI) is described here.
If you don't want to read this tutorial and just download the resulting product follow this link: 
What is workflow?
In Plone Cms a workflow is a kind of a policy. The policy deals with what rights a user has on a piece of content in the different states. The workflow can be defined as states and transitions between the states. Sounds weird? Let's look at an example: The Simple Show Hide Workflow.
The Simple Show Hide Workflow
I imagine the use case where all content is visible by default. But I can easily anticipate problems with having all contents visible at all times; perhaps a discussion in a forum turns into a flame war or contains inappropriate language. In such cases I want to be able to hide the bad content to allow managers to not be forced to remove it. This could be some middle station before risky content is deleted.
So I want my workflow to contain two states:
- Everybody can view the contents and managers and the owner of the content can edit it. This is to be the default state. I get the impression that this state has to be called Published, which is fine by me.
- Another state where only the owner and managers can view it. I call this state Hidden.
To switch between states we need two transitions:
- Hide: A manager decides to make published content hidden.
- Unhide: The hidden content has been rewritten or it was no reason for it to be hidden in the first place, so the manager unhides it. (I could use the term publish for this since the state I end up in is a published state - but the term unhide gives me a feeling of going back to the default state - the state that is not hidden.)
I found one way of working with workflows (inspired by numerous tutorials out there) is to follow this pattern:
- Copy, Paste and Rename an existing workflow.
- Add/Remove states and transitions.
- Modify the states and transitions.
- Set your custom workflow to be active on your custom content type and test it.
- Export in via Portal Setup -> Export
- Rehack the xml-files (this is the part where you need to be careful).
- Insert your custom workflow in a product (in this tutorial the same as the content type).
- Try it and see if it works by installing it on a blank Plone site.
In the rest of this tutorial I will try to illustrate how I do these steps - I am pretty sure there are more ways of doing it.
Let's do it, let's make our own custom workflow
Before we continue we need to take a deep breath and remember that Fear Is The Mindkiller:
I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain.
Ok, we are now ready to continue.
Copy, Paste and Rename an existing workflow
In ZMI I copy a workflow that is as similar to what I want as possible (I hope). In my case the folder-workflow. I rename it simple_show_hide_workflow. Doing so looks a little something like this:
Add/Remove and modify states and transitions
Now I remove all states except two. I rename one of them hidden. I make the published state the default one. Under states -> hidden -> permission I also give manager all rights and allow view to editor and owner. The permissions on the published state are plain vanilla.
In the transitions I specify what their "Destination state" is, and that Manager guards the hide action. The publish transition (called unhide) is guarded by the permission "Modify Portal Content" - that's ok since only the manager is allowed to modify hidden content.
The transitions view now looks something like this:
Set your custom workflow to be active on your custom content type
I want to modify the content type created in Plone Simple Folder And Permissions so I install it and under portal_workflow I manually specify simple_show_hide_workflow under the types I want.
I can now test this by adding content of these types and indeed it seems to do what I want.
Export in via Portal Setup and Rehack the xml-files
In portal setup under the tab export I select the second title: Workflow Tool and export only that step.
I save the big chunk of xml in a folder. The content looks something like this:
workflows.xml workflows/folder_workflow/definition.xml workflows/intranet_folder_workflow/definition.xml workflows/intranet_workflow/definition.xml workflows/one_state_workflow/definition.xml workflows/plone_workflow/definition.xml workflows/simple_publication_workflow/definition.xml workflows/simple_show_hide_workflow/definition.xml
Since the only addition from the defaults is the simple_show_hide_workflow we can remove everything but these two items:
The file workflows.xml is then trimmed to remove everything that seems to deal with other workflows into this:
<?xml version="1.0"?> <object name="portal_workflow" meta_type="Plone Workflow Tool"> <property name="title">Contains workflow definitions for your portal</property> <object name="simple_show_hide_workflow" meta_type="Workflow"/> <bindings> <type type_id="SimpleFolderWithWorkflow"> <bound-workflow workflow_id="simple_show_hide_workflow"/> </type> <type type_id="SimpleThingWithWorkflow"> <bound-workflow workflow_id="simple_show_hide_workflow"/> </type> </bindings> </object>
The file workflows/simple_show_hide_workflow/definition.xml is left untouched.
Insert your custom workflow in a product
I modify the content type from Plone Simple Folder And Permissions into a package with the following contents:
__init__.py config.py configure.zcml simplefolderwithworkflow.py Extensions/Install.py profiles/default/workflows.xml profiles/default/workflows/simple_show_hide_workflow/definition.xml
One of the new things is the configure.zcml - this is needed for the generic setup:
<configure xmlns="; xmlns:browser="; xmlns:gs=";> <gs:registerProfile name="default" title="SimpleFolderWithWorkflow profile" directory="profiles/default" description="" provides="Products.GenericSetup.interfaces.EXTENSION" for="Products.CMFPlone.interfaces.IPloneSiteRoot" /> </configure>
I also do some modifications to Extensions/Install.py
# imports def addToFactoryTool(self, out): # as before def install(self): # starts like before with installing the types ... # do the generic setup stuff tool=getToolByName(self, "portal_setup") profile = "profile-Products.%s:default" % PROJECTNAME try: tool.runAllImportStepsFromProfile(profile, purge_old=False) except AttributeError: # before plone 3 tool.setImportContext(profile) tool.runAllImportSteps(purge_old=False) print >> out, 'Ran all import steps.' return out.getvalue()
That should be it!
Download here: