Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Multi-Workflow Support for Plone

collective.multiworkflow

PyPI PyPI - Python Version PyPI - Plone Versions

GitHub contributors GitHub Repo stars

CI

The backend package for Multi-Workflow Support for Plone — a Plone 6.2 add-on that assigns additional workflows to content types through behaviors, and carries them through the catalog, the REST API, and Volto. See also the frontend package @plone-collective/volto-multiworkflow.

Features

When a content type provides a participating behavior, this package appends one or more additional workflows to that type's workflow chain. The type's configured chain is never replaced, and content that does not provide the behavior is left completely untouched.

  • Behavior-driven chains — a behavior marker interface extends IAdditionalWorkflows and declares the workflow ids it contributes with one ZCML directive. A workflow chain adapter, registered for that marker, appends them to the type's existing chain.

    <configure xmlns:plone="http://namespaces.plone.org/plone">
      <plone:additionalworkflows
          marker=".interfaces.IFoundationMember"
          workflows="foundation_member_workflow"
          />
    </configure>
    

    workflows is a whitespace-separated list, appended in the order given. A marker that does not extend IAdditionalWorkflows raises ConfigurationError while the ZCML is read, rather than being ignored at runtime. The directive is available as soon as this package is installed — Products.CMFPlone auto-includes add-on meta.zcml — but a package that wants to be explicit can <include package="collective.multiworkflow" file="meta.zcml" /> first. For contributions ZCML cannot express, the contributes() factory the directive wraps stays public.

  • Deterministic composition — the base chain order is preserved, contributed workflows are appended in interface resolution order, and duplicates are removed. A contributed workflow id that does not exist in portal_workflow is logged and skipped rather than breaking chain lookup.

  • review_state is never affected — each additional workflow uses its own state_variable, so Plone's publication workflow behaves exactly as before.

  • Workflow-aware helpersget_state, get_states, transition, and transitions read and drive per-workflow state. Their defaults reproduce today's plone.api behavior exactly. conflicting_permissions audits a chain for workflows claiming the same permission.

  • REST API — on participating content, the @workflow endpoint gains a chain key with one entry per workflow (workflow_id, title, state, state_variable, transitions, history), and its top-level transitions list is narrowed to the primary workflow, so a client written before this package cannot present an unrelated workflow's transitions as publication actions. @history merges every chain workflow's transitions into the single time-sorted stream it already returns, tagging every entry with a workflow_id (null for versioning entries). Both are registered on the marker interface, so content that provides no participating behavior is served core's payload untouched — with no chain key at all, which is what a client should test for.

  • Catalog support — the installation profile adds one workflow_states KeywordIndex describing an object's whole chain, so a site gains no further indexes as behaviors contribute more workflows. Values read <workflow-id>|<state-id> and are in chain order; build them with format_state() and read them back with parse_state(). Parsed review_state collection queries are rewritten onto it, so collections written before the add-on keep working.

  • Import-safeplone.exportimport restores workflow state by assigning workflow_history directly, which fires no transition and so leaves an additional workflow's catalog entry stale. collective.multiworkflow.exportimport patches the importer to reindex what it changed. The patch is generic, names no index of this package's own, and is written to be moved upstream.

  • Fully typed — every public API is annotated, mypy runs over the package in CI, and a PEP 561 py.typed marker ships in the wheel, so consumers type check against this package rather than around it.

Requirements for additional workflows

An additional workflow may manage permissions. DCWorkflowDefinition rewrites only the permissions listed in its own permissions, and executing a transition re-applies the mappings of the transitioning workflow alone, so workflows sharing a chain compose as long as their permission sets do not overlap.

  • Declare workflow_states as the state_variable; never review_state. Using the same name as the catalog index is what makes WorkflowTool._reindexWorkflowVariables keep that index fresh on every transition, with no subscriber involved. Sharing the name across workflows is safe, because DCWorkflow keys its status records by workflow id rather than by variable name. A workflow keeping a bespoke variable still works: an event handler reindexes for it, but only when nothing else will.
  • Keep transition ids unique across every workflow in a type's chain.
  • Keep managed permissions disjoint across the chain. Where two workflows claim the same permission, the mapping is left as whichever transitioned last wrote it, and stays that way until the other transitions or portal_workflow.updateRoleMappings() runs. conflicting_permissions(obj) reports the overlap for a given object.

Not in scope

  • Placeful workflows (CMFPlacefulWorkflow) integration.
  • Sub-workflows — a transition in one workflow triggering another. The chain model is concurrent, not hierarchical.
  • Reconciling workflows that manage the same permission — the package reports the conflict rather than arbitrating it.
  • Any change to review_state semantics.

Trying the example

The package ships an example — a foundation_member behavior and a foundation_member_workflow that tracks a membership lifecycle — but installing collective.multiworkflow deliberately does not add a behavior to your site. The example lives in the collective.multiworkflow.demo subpackage, which the root configure.zcml never includes, so neither the behavior nor its demo profile exists in a plain installation.

To see it running, load that package's ZCML explicitly and apply its profile. This repository's instance.yaml already does the first part for local development:

zcml_package_includes: 'collective.multiworkflow,collective.multiworkflow.demo'

then install the collective.multiworkflow.demo:demo profile. make create-site does both.

Documentation

Full documentation is published at collective.github.io/collective-multiworkflow, and its source lives in docs/ at the repository root.

The pages closest to this package are the Python API reference, the ZCML directive, the catalog index, and the REST API, whose request and response examples are generated by this package's own test suite, in tests/docs/.

Installation

Install collective.multiworkflow with uv.

uv add collective.multiworkflow

Create the Plone site.

make create-site

Contribute

Prerequisites ✅

Installation 🔧

  1. Clone this repository.

    git clone git@github.com:collective/collective-multiworkflow.git
    cd collective-multiworkflow/backend
    
  2. Install this code base.

    make install
    

Add features using plonecli or bobtemplates.plone

This package provides markers as strings (<!-- extra stuff goes here -->) that are compatible with plonecli and bobtemplates.plone. These markers act as hooks to add all kinds of features through subtemplates, including behaviors, control panels, upgrade steps, or other subtemplates from bobtemplates.plone. plonecli is a command line client for bobtemplates.plone, adding autocompletion and other features.

To add a feature as a subtemplate to your package, use the following command pattern.

make add <template_name>

For example, you can add a content type to your package with the following command.

make add content_type

You can add a behavior with the following command.

make add behavior
You can check the list of available subtemplates in the [`bobtemplates.plone` `README.md` file](https://github.com/plone/bobtemplates.plone/?tab=readme-ov-file#provided-subtemplates).
See also the documentation of [Mockup and Patternslib](https://6.docs.plone.org/classic-ui/mockup.html) for how to build the UI toolkit for Classic UI.

License

The project is licensed under GPLv2.

Credits and acknowledgements 🙏

Generated using Cookieplone (2.0.0b3) and cookieplone-templates (61a8f90) on 2026-08-07 16:01:41.322560. A special thanks to all contributors and supporters!

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

collective_multiworkflow-1.0.0a1.tar.gz (238.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

collective_multiworkflow-1.0.0a1-py3-none-any.whl (226.2 kB view details)

Uploaded Python 3

File details

Details for the file collective_multiworkflow-1.0.0a1.tar.gz.

File metadata

  • Download URL: collective_multiworkflow-1.0.0a1.tar.gz
  • Upload date:
  • Size: 238.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for collective_multiworkflow-1.0.0a1.tar.gz
Algorithm Hash digest
SHA256 47e465e71710377b39fd22a54f18f68136a183b2512cb76288ab2f5d98015936
MD5 5c51c89743847963dfbc45c35191d048
BLAKE2b-256 fed6368c7e856c686b6e97cecd7e590f9a3f590e2a9557f3ac2124426420d5ca

See more details on using hashes here.

File details

Details for the file collective_multiworkflow-1.0.0a1-py3-none-any.whl.

File metadata

  • Download URL: collective_multiworkflow-1.0.0a1-py3-none-any.whl
  • Upload date:
  • Size: 226.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for collective_multiworkflow-1.0.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 b7eb91d1fcd11e3a168d3026f06402ac05d45cf6e25e44192a121169ac7e86e0
MD5 dc2b156b19a7f8d426467720b19cb8bf
BLAKE2b-256 2f3925323afa38f6697011e993cc95a43875d7f2910ebffef9521963bcbaba38

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page