How to copy and paste content with workflow states (UI)?

Default behavior is pasting with setting workflow states to workflows initial state.
How can a user paste and keep the original workflow states?

Idea behind this, if you create a copy it should be handled like newly created content. So, OOTB it does not work.

I had the same need somewhere in past and created a subcriber to zope.lifecycleevent.interfaces.IObjectAddedEvent event checking some contraints and then transition to the desired state. (Do not ask me details, sorry, I can not remember where I have the code for this). HTH

1 Like

Thank you. I thought of a subscriber. Hoped there is another solution.

Here is what works for me. It's not elgant.
Unfortunatly IObjectCopiedEvent knows about review_state, but the event handler cannot set review_state, IObjectAddedEvent knows about new object and event handler can set review_set, but does not know old review_state. So it seems necessary to use both events.

  <subscriber
      for="plone.dexterity.interfaces.IDexterityContent
           zope.lifecycleevent.interfaces.IObjectCopiedEvent"
      handler=".eventhandler.setWorkflowstateCopied"
   />
   <subscriber
       for="plone.dexterity.interfaces.IDexterityContent
            zope.lifecycleevent.interfaces.IObjectAddedEvent"
       handler=".eventhandler.setWorkflowstateAdded"
    />

eventhandler.py:

def setWorkflowstateCopied(obj, event):
    """An object has been copied

    original = Attribute("The original from which the copy was made")
    """
    annotations = IAnnotations(obj)
    obj_old = event.original.restrictedTraverse(
        "/".join(list(obj.getPhysicalPath())[1:]))
    review_state_old = api.content.get_state(obj=obj_old, default=None)
    annotations['review_state_old'] = review_state_old


def setWorkflowstateAdded(obj, event):
    """An object has been added to a container"""
    annotations = IAnnotations(obj)
    review_state_old = annotations.get('review_state_old', None)
    if review_state_old:
        api.content.transition(obj=obj, to_state=review_state_old)
        logger.info(
            "object {} copied and review_state set to {}"
            .format(obj, review_state_old))
        del annotations['review_state_old']
1 Like

The behaviour (of resetting the copy's state to the initial state) always seemed 'wrong' to me too. I wonder what could set review_state directly? Also if there could be two Paste actions, the current one and one that maintains the state.

1 Like

Or have a configuration somewhere in the controlpanel where the paste functionality is defined.

Or (imo better) have a behavior "plone.keepstateaftercopy" which can be configure per content-type.