Problem/Motivation
When reverting to a previous revision of an item of content, the new revision created matches the moderation state of the revision being reverted.
While this keeps the integrity of the workflow intact, since content can only be recreated in a state that was valid at some previous point in time, it may not always be what users expect and it limits the utility of reverting in general, since certain revisions can only be recreated and immediately published or can only be recreated and reverted back to a draft.
Steps to reproduce
- Create a draft Node e.g. titled Test v1
- Create a new draft e.g. titled Test v2
- Publish Test v2
- Decide you prefer Test v1 but want to tweak it first before republishing
- Click revert: Test v1 is immediately published and tweaking it first is not possible
Proposed resolution
The proposed resolution is to modify the revision revert confirmation form to include a moderation state select list. This will allow the user to select the desired moderation state for the new revision being created. The list of available moderation states will be filtered to only include those that the user has the permission to transition to.
Remaining tasks
- ☑ Update the revision revert form to include the moderation state select list.
- ☑ Add logic to filter the list of available moderation states based on user permissions.
- ☑ Update the form submission logic to save the selected moderation state to the new revision.
- ☑ Ensure the available workflow transitions and permissions are taken into account per #74.
- ☑ Add and update tests to ensure the new functionality is working as expected.
But there is one outstanding comment whether this should be set up to more broadly cover moderated content beyond Nodes. Addressed in comment #86.
User interface changes
A new "Moderation state" select list will be added to the revision revert confirmation form.

Introduced terminology
None
API changes
None
Data model changes
None
Release notes snippet
The confirmation screen for reverting Nodes when Content Moderation is enabled now let's the editor decide whether to revert to a particular moderation state. Previously reverting would always publish the older revision.
| Comment | File | Size | Author |
|---|---|---|---|
| #123 | 2906568-123.patch | 22.86 KB | nitinkumar_7 |
| #122 | drupal_2906568__2026-05-19.patch | 22.86 KB | opi |
| #120 | gin.PNG | 385.4 KB | rkoller |
| #120 | claro.PNG | 378.5 KB | rkoller |
| #107 | mr.mp4 | 1.86 MB | rkoller |
Issue fork drupal-2906568
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
sam152 commentedDo we just need to match the default-ness of the revision being reverted to? Ie, if you revert to a non-default draft revision, it becomes the latest and pending revision? Huge UX head-scratcher either way!
Comment #3
catchComment #4
sam152 commentedComment #5
cburschkaOkay, the specific condition under which this is a problem seems to require the following:
- There are two distinct states A, B; and B has the content_moderation setting
default_revision.- The node's default revision has workflow state A.
- The user reverts to a non-default revision with workflow state B.
- The user does not permission to change the state from A to B.
(In specific, this happens if you have a default Draft or Archived revision, and revert to an older Published revision. Also if you have a default Published revision and revert to an older Archived revision. It's not a problem if you revert to a Draft, because that simply creates a forward revision.)
Comment #6
cburschkaUX-wise, it would be ideal to allow access to the revision list and allow reverting in general, but check the specific case:
- If the target revision has a different state than the current default.
- And that state moves the default revision
- Find the transition corresponding to that state change
- And check that the user is permitted to access it.
We also need to show each revision's workflow state in the revision list, because otherwise it would be completely intransparent which revisions you can revert to. (Edit: #2612222: Provide a better way to alter entity revision overview impedes that part.)
Comment #7
cburschkaUpdate: If #2899719: Revision/version language on revision listing page is misleading with content moderation enabled is resolved by unconditionally setting the default revision, the transition will need to be checked regardless of whether the state would normally set the default revision.
Comment #8
sam152 commentedI don't think we should be validating this. We are reverting to a revision which was previously already "allowed". The question of if the state of the current revision can transition to the state we're reverting to is kind of irrelevant right? Conceptually we're going back in time, not creating something new based on something that exists.
Comment #9
cburschkaSo would you say that reverting revisions simply trumps all the content moderation permissions, such that a reverter can restore the node to any workflow state it has previously been in?
For example, this would mean that you can't permanently Archive a node while still giving revert permissions to editors. Anyone could simply undo the Archive transition by reverting to the Published version.
Comment #10
sam152 commentedTo me that's what "revert permissions" is, restoring some previous state despite other circumstances. I understand what you're saying, but it seems like there could be a whole seperate set of issues to be able to replicate content_moderation semantics in another interface that is fundamentally concerned with something else, ie going back vs going forward.
My interests are mostly based in keeping things simple and reducing the surface area of edge cases that will need to be handled.
Comment #11
cburschkaThat makes sense - if we take this approach, then I guess the issue would be works-as-designed, and we only need to add some documentation for it.
It's certainly simpler if we consider revision-reverting to happen on a level below business logic like moderation, since the moderation state is part of the revision. After all, we also don't revalidate any of the other fields either, which also might contain special logic that would prevent the old revision's values to be entered manually.
Comment #12
sam152 commentedRight! One thing I'm unsure of though is reverting to a revision which was never default. That is, for a draft, should that create a new pending draft revision instead of a default draft revision? I haven't actually tested this but would be interested to see how it behaves. My understanding was based on the following from the IS:
Comment #13
cburschkaCurrently, the decision whether or not the new revision becomes default seems to be the same for reverting as for editing. That is, reverting a never-published node to a draft revision sets it as a default, reverting a published node to a draft creates a pending revision, and reverting to a published revision makes it the new default. (This is what I've found, at least.)
I don't believe it is possible to revert to a never-default revision and make the new revision default. If it was never the default revision, then it was created as a pending revision. Reverting to it applies the same logic as before, so the new revision should be a pending revision as well.
As far as I understand, this refers to making the node published (again) by reverting to a revision that was already published once. (Please correct me if that's wrong, @catch)
Comment #14
sam152 commentedOkay, perhaps if that's the case I misunderstood the IS and @catch's thoughts were aligned with #9.
In any case, if content_moderation is providing the defaultness-matching part, that should probably be moved to core. The more pending revisions work from an API level by themselves, the easier time we'll have with workspaces (or any other user of pending revisions) which will be utilising the same api without content_moderation necessarily being installed.
We can write a test for this using the
isDefaultRevision,setNewRevisionmethods and see what happens when we do a revert.Comment #16
sam152 commented#2891215: Add a way to track whether a revision was default when originally created might end up helping with this issue.
@catch, any thoughts on the approach to solving this?
Comment #17
catchAdding the usability review tag.
A few ideas, I'm leaning towards the first option if it turns out to be viable, since it could then be acceptable for both workspaces, content moderation and any other module that's doing things with pending revisions.
- only allow reverts to default revisions (will depend on the new field being added) - assume that any module using pending revisions will have it's own, separate UI to make them public. Possibly have default and pending tabs on that page that show one or the other. This would probably be a straight change to that tab that just makes it more robust for different use cases.
- completely override the tab when content_moderation (and later workspaces) is installed.
- alter the access for the revert action to also require some kind of content_moderation permission
- leave it as is, but probably with some messaging (this seems like the worst option, I think we should probably do one of the first three).
Comment #18
jhedstromCould we simply add the moderation select list to the revert confirmation form?
That would inherit the current user's permissions to which transitions they could make, so when reverting to a previously published revision, if they didn't have that permission, they could only revert it to a draft, etc.
Comment #19
jhedstromHere's a rough start on adding the moderation state to the revert form. Due to the way the
NodeRevisionRevertFormsaves the revision, a simple form alter would not work here.I'm working on some tests now, but wanted to post this here to get feedback on the general approach.
Comment #20
timmillwoodThis looks awesome so far. Would be good if you could demo it on the UX call on Tuesdays.
One issue I see, from a UX point of view is, why do I need to select a moderation state?
Comment #21
jhedstromCertainly. I think the UI here could use some work in terms of wording. For users that, for instance, didn't have permission to transition from a published state, the UI remains as it is now, but the reverted revision comes in as draft instead of published as it would now.
This adds a test for the current behavior of the patch.
Comment #22
jhedstromI realized that the approach above for determining allowed transitions was slightly flawed. Since the goal here is not to bypass content moderation, we want to check which transitions the current user has permission to from the
defaultstate of a new revision, rather than which transitions they have access to away from the revision to be reverted.This patch makes that change.
Comment #23
jhedstromAfter some feedback, I'm thinking this isn't quite the correct approach either. For instance, if there is a published version, and somebody reverts and selects
draftas the target state, then the published version goes away. Instead, available transition states should perhaps be calculated from the latest published version (if it exists), and falling back to the latest revision.Comment #24
kevin.dutra commentedAlthough the tests are still able to apply the patch, this now collides with work introduced in #2940899: Regression: _entity_form routes should not get load_latest_revision_flag by default: changes default behavior (= regression) while only Content Moderation needs it. (There are now two services with the same name.)
Comment #25
timmillwoodWe should be able to update the patch here to make use of the same route subscriber.
Comment #28
almunningsRolling for 8.7
Just added the methods as before, but reusing the subscriber.
Comment #30
sam152 commentedNice work on this @jhedstrom, but I'm not sure this approach makes sense either.
When reverting to a previous revision, we aren't transitioning any of the content from the latest revision, so I don't think the states available from that revision make sense. Imagine someone has the permission to use the "Publish approved content" transition. If the latest version is "Approved", they'd have access to use "Published" on that specific content, but it doesn't imply they'd have access to publish any content in the revision history.
For that reason, I don't think any of the current workflow transition permissions are appropriate for this use case. I think each workflow would need a new permission per state called "Revert as $state", where the default fallback when none of these permissions are granted is that the reverted revision matches the original state of that revision.
Using this implementation, any new behaviour is guarded behind new permissions and the existing behaviour is preserved if site builders do nothing. I believe it introduces the least amount of assumptions and provides the most safety for existing installations.
I'm going to rejig the issue summary and title to match the direction this issue is going in and I likely have some time to work on this. It might be that this implementation doesn't pass framework/product/usability reviews, in which case I think it'll be a great implementation for a contrib module and my vote would be to close the existing issue as "Works as designed".
Comment #31
sam152 commentedComment #32
sam152 commentedThis is just a progress patch, I'm going to continue working on this. Currently still needs:
ModerationRevisionRevertTest.Comment #33
sam152 commentedComment #34
sam152 commentedAnother progress patch, still needs some testing. I think I also need to validate that
::createRevisionshould be used on the node revert form. The translation affected status gets messed up otherwise. Seeing what the testbot thinks.Comment #35
sam152 commentedComment #36
mpp commentedI like the UI/UX part to select the moderation state.
However, when I revert a revision to 'draft', I'd expect the current published revision to remain published but now the node is unpublished. How can I make sure that forward revisions are enabled?
Comment #37
sam152 commentedI agree, if the patch isn't doing that, I believe something is not quite right. I will follow-up and hopefully add some tests along the way.
Comment #38
sam152 commentedFixing tests and expanding the test coverage.
Comment #39
sam152 commentedComment #40
mpp commentedPatch looks good, thank you!
This should happen through the constructor.
Comment #41
sam152 commentedUsing constructor injection requires the subclass to change when the constructor of the base class changes and is also more verbose. I don't really see the point if the class isn't being unit tested.
Comment #43
acbramley commentedDo we want to mention here that it could immediately unpublish the content as well?
Very nice description 👌
Should this not use
$this->nodeStorage?Nice work on these tests, this is testing that not only the revert is working, but that it's not overwriting the default revision state 👏
Only small nits from me so leaving in NR for now.
Comment #44
ryan.ryan commentedPatch applies cleanly and works in my testing. From a UX perspective, I may make an argument for it being part of the revision dropdown, but this is a good start.
Comment #45
sam152 commentedThanks for the review @acbramley. Marking NW for those points.
Comment #46
ravi.shankar commentedWorking on this, it needs a re-roll also.
Comment #47
ravi.shankar commentedHere I have added a re-roll of patch #38 and I have tried to address point no. 3 of comment #43.
Comment #49
acbramley commentedPatch #38 still applied fine, please ignore #47.
Comment #50
acbramley commentedFixed #43
Comment #51
acbramley commented@dpi brought up a very good point that this is Node centric at the moment. With #2350939: Implement a generic revision UI we could make this generic enough to apply to any entity type using content moderation. Do we want to block this issue on that?
Comment #52
dpiComment #53
benjifisherWe looked at this issue at the #3173646: Drupal Usability Meeting 2020-09-29.
I am setting the status to NW and adding the tag for an issue summary update. Before we can give a proper usability review, please
I am also fixing a typo in the issue summary.
Comment #55
azinck commentedFor all the sites I've built, I don't really want any of the things being asked for in this thread. In fact, I would ideally prefer the old core behavior (before this: #2809123: Reverting a revision doesn't keep moderation state) be restored.
Specifically I'd argue that "reverting" a revision should create a copy of that revision in the "default" moderation state (draft) so that it can go through the content moderation process again.
It avoids all the difficulties of having to figure out complicated permissions, and limits the number of weird edge-cases and additional content moderation considerations (consider that this is yet another code path for effectively "publishing"). Keep it simple: if someone is allowed to edit a node then they should be able to revert an old revision, making a new draft based on it.
But I assume I must be in the minority here. I just don't see a big upside to allowing reversion into a specific moderation state, and it seems to add a fair bit of complexity.
Comment #56
sam152 commented@azinck, the proposed approach solves your use case. You could only grant access to revert to draft and then it works in the same way before the bugfix you linked.
The problem with always assuming draft, is you're conflating access to revert something, with access to assigning the 'draft' state to a revision. A workflow or site may not be configured to allow the given user to create content in that state.
Comment #57
azinck commented@Sam152: thanks for the response. Yes, I recognize my proposed solution is, indeed, different, with different trade-offs than what has been discussed on this thread so-far.
I'm suggesting that, from my experience actually implementing content moderation on a variety of sites as a consultant, the solution I described maps onto how my clients expect things to work, is relatively simple to implement, and resolves some of the more challenging UX problems and permissions edge-cases.
I agree that it is less flexible than what has been discussed here, and we are already doing what you suggest (limiting users to only being able to revert to draft) in order to achieve our goals. The work in this issue is probably far enough along that it's worth continuing, but I did want to put out there what my experience has been in the real world, and consider that as a possible way to resolve some of the trickier aspects of this problem.
Comment #58
sam152 commentedThe issue with implementing your simplified approach and not continuing work on the current approach is, it changes the behavior of existing installations, which I can say from experience is a good way to ruffle a lot of feathers.
Comment #59
oktboy commentedWe are using Content Moderation with groups. I tried Patch 38 and 50 through 'composer update' but keep getting error on Drupal 9.1.0
Could not apply patch! Skipping. The error was: Cannot apply patch https://www.drupal.org/files/issues/2020-06-25/2906568-50.patch
Modules used as well:
Workflow
Group
Group Permissions
Content Moderation Notifications
Anyone can point me in the right direction to debug that would be great.
Comment #60
larowlanreroll
Comment #61
sam152 commented@oktboy and any others looking at this issue, I would probably opt for the module implementation (https://www.drupal.org/sandbox/sam/3118829) over a patch if you need this feature today, since this is a fairly experimental patch that may not get signed off.
Comment #63
nikitagupta commentedRerolled patch #60.
Comment #64
nikitagupta commentedfixed drupal CI issue.
Comment #65
nikitagupta commentedfixed drupal CI issue.
Comment #66
kim.pepperComment #67
donquixote commentedInteresting stuff.
----
@azinck (#55), @Sam152 (#56):
I think the scenario described by azinck is quite common. A project I work on has a similar situation, where we want "Revert" to copy the revision as a new draft (= forward revision), which should then be published as a separate operation.
This said, I am happy with the solution proposed in this issue, if it can be configured to cover the described scenario - which seems to be the case according to Sam152 - so fine for me.
-----
For the available workflow states for the reverted revision, we should take into account whether this is the latest forward draft revision, or any other forward revision, or a past revision.
For a latest revision, I never want to "Revert", instead i want to "Publish". This should also be reflected in the button/operation label in the revision list.
Without this, the workflow described by @azinck in #55 would not work.
If "Revert" copies the revision as draft, and you are sent back to the revision list, you now need a button to actually publish that latest revision that was just created.
If there are multiple forward draft revisions, I am not really sure how we should handle the non-latest ones.
In my opinion, they should be treated the same as past revisions. A colleague I talked with had a different opinion, and thinks they should be treated the same as the latest revision, with a "Publish" button.
Comment #68
azinck commented@donquixote: I disagree with the idea of putting a dedicated "publish" button anywhere on that revision list page. Publishing isn't always the only valid state for all latest revisions (it's not even always *a* valid state for some forward revisions in some workflows) .
In my mind, the behavior should be exactly the same for all non-current revisions regardless of whether they're forward revisions or not. This patch calls the action "revert and set to" which makes sense for past revisions, but not for the latest revision (which is what is tempting you to call it "publish", I think). I might suggest calling it something like "transition state", or "change state", or "clone to new state" or something similar that makes sense no matter which revision it is. Choosing that action should bring up the form provided in this patch for choosing from the valid destination states. Then the operation would clone the revision and set it to its destination state, and, if appropriate, make it the default (current) revision.
Comment #69
donquixote commentedA site builder might want to narrow down the valid destination states through configuration, such that only "draft" is available.
But this would not be suitable for the latest revision. Otherwise, new redundant forward draft revisions will pile up.
After copying an older revision as a new forward draft, the user will end up on the revision list, and now they want an option to publish the latest revision - or ask somebody else to do it.
Comment #71
azinck commented@donquixote: Yeah, all of the confusion here is why I don't love the approach of allowing arbitrary transitions to occur via this UI. These aren't even "real" transitions...so all of the existing permissions and restrictions around transitions no longer apply. And you might have code that is responding to revisions entering a particular state that only expects a subset of possible source states, but this functionality completely breaks that assumption since it allows ANY source state to go to ANY destination state.
I think there are so many edge cases here that it's going to get super messy. That's why I still personally like my suggestion of "revert" merely allowing a revision to be copied as the latest revision and set to the default workflow state. Then all other workflow stuff gets accomplished and enforced via the normal means.
Comment #74
fernly commentedI used the patch from #60.
Changing the moderation state for a revision works, but it allows all states to be chosen. The workflow transitions and permissions are not taken into account. This way any editorial user can publish content without having the permission to do so.
Comment #75
ravi.shankar commentedAdded reroll of patch #65 on Drupal 10.1.x, keeping the status needs work for comment #74.
Comment #76
acbramley commentedFixed the failure. I don't think #65 is valid considering we have tests covering this functionality.
Comment #78
acbramley commentedFixed comparison of strings vs FormattableMarkup, added return types.
Comment #79
manuvelasco commentedThe patch on #78 works for me just for sites without translate content enabled, that is because the route for content with translation is node.revision_revert_translation_confirm so we should also add a form for these cases and assign it to the mentioned route.
Comment #81
smustgrave commentedThis would be a great feature to have. Can we update the issue summary with the agreed upon solution though?
Also have posted in the #ux for usability review so hopefully happens soon.
Comment #84
mstrelan commentedRe-rolled and created MR against 11.x
Comment #85
mstrelan commentedHad the same thought as #51, this is very specific to nodes and I'm not sure it needs to be.
Comment #86
acbramley commentedRe #85 - it doesn't need to be but we are quite a way off using the generic UI for Nodes.
Comment #87
ericgsmith commentedAdding patch of MR5696 at commit 3ba5a1a1 for anybody needing a stable patch against 10.2
Comment #88
jlongbottom commentedWhen I revert a revision to Draft, it is updating the published SQL table for my field (eg: paragraph__field_X), as well as creating a new row in the revisions table (paragraph_revision__field_X). This does not happen when you make a new Draft by normal editing of the node - only when you revert to a draft.
I noticed this because I have some custom code elsewhere that is manually querying the published SQL table for my field and I was surprised to find the reverted draft values instead of the published values.
It looks like we call
prepareRevertedRevisionwhich is hard-coded to$revision->isDefaultRevision(TRUE);. Is this correct? Seems like it should be false if reverting to a draft.or maybe something like this
Comment #89
jlongbottom commentedThat seemed to have fixed the issue for me. Attached is my patch.
Comment #90
jlongbottom commentedPatch updated with translation support
Comment #91
jlongbottom commentedUpdated route subscriber to work on multilingual sites by checking for
node.revision_revert_translation_confirmComment #92
opiAnyone else struggling to patch against 10.3.0 ?
Comment #93
mstrelan commented@opi I've attached the patch we're using for 10.3.0, but I have set it to hidden so as not to confuse this issue further. This is based on the patch in #87 as that's what we were previously using and I haven't reviewed 89-91, which don't have interdiffs and aren't in sync with the MR.
Comment #94
opi@mstrelan Thanks a lot ! I wasn't brave enough to rebase a 21KB patch last evening <3
Comment #95
jlongbottom commentedre-rolled against 10.3.1, but I did not bother with the tests
Comment #96
scott_euser commentedUpdated issue summary. I believe there is one outstanding comment whether this should be set up to more broadly cover moderated content beyond Nodes.
Comment #97
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #98
acbramley commentedRebased the MR and hiding patches to not confuse the bot.
Comment #99
acbramley commentedComment #100
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #101
scott_euser commentedComment #102
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #104
opiMR patch file doesn't apply on latest Drupal core 11.3.2 ...
Comment #105
acbramley commentedRebased against main
Comment #106
opiThanks a lot @acbramley , works like a charm on 11.3.2 !
Seems to be RTBC
Comment #107
rkollerWe've discussed this issue at the usability meeting #3577382: Drupal Usability Meeting 2026-03-13 yesterday. While writing up the summary i did some more testing and that additional experimentation raised a few questions in regard to our conclusions during the meeting. So I just wanted to ask for clarification before finishing the write up of the summary.
1. on the main branch without content moderation active, when you revert to a revision, that revision becomes active and you are able to edit it on the node edit form (main_without_cm.mp4). if you do the same step with content moderation installed the current revision remains the last published revision before the revert (main_with_cm.mp4) - same for the merge request checked out (mr.mp4). was that a misconfiguration on our end or is it impossible to actively edit a reverted version of a node afterwards.out of scope for this issue, but just trying to understand the overall problem space, cuz at least myself i am not that familiar in depth with the content moderation module.
2. on the confirmation step, does
revision moderation steprefer to the moderation state the current node has or does it refer to the state the revision has the node will be reverted to? (*during the meeting we've understood "revision moderation state" would refer to the state of the current revision not the one the node is reverted to - but the additional experimentation made me question that assumption)Comment #108
acbramley commentedre 1. IIRC with CM - if you have an active published revision and then revert an old revision to Draft you can then edit that new Draft.
re 2. it's the moderation state for the revision that is created by the revert, it does not change the state of the revision you are reverting from.
Comment #109
acbramley commentedRebased with main and we have a failure, also need to:
1. Remove service id and use class name for aliasing
2. Add return types to everything new
3. Add strict_types to new class
4. Remove boilerplate cruft in PHP docs
We can probably also remove the interface from the service.
Comment #110
rkollerthanks for the rebase @acbramley and apologies for the delay. i went into a rabbit hole over the course of the last week experimenting and trying to understand the whole problem space of the content moderation module figuring out what threw us off last friday that lead us into question two in #107. I understand things now finally. I havent completely finished the write up but most likely will raise this issue for a second round tomorrow. cuz the recommendation we've agreed on for question one in #107 was based on a false assumption. so i would like to revisit this issue a second time - always better for more complex problems. will post the combined summary afterwards. but one small problem/bug i'Ve noticed function wise while experimenting. steps to reproduce are as follows:
Comment #111
acbramley commented@rkoller what state did you select during the revert?
Comment #112
rkollerwoops forgot to mention that detail. i kept the default aka the state the revision i reverted to is in:
draftComment #113
rkollerThe problem not only applies for that reverted revision example. also happens if you do:
so maybe not related to the MR after the problem also applies if the confirmation step is not used? but in any way, editing a node on the moderated content list view is pointing to the wrong revision
Comment #114
acbramley commentedThis is correct behaviour, unless that's a typo?
Can you try to reproduce this with a clean install off main branch? what you've described in #110 would be a serious bug.
Comment #115
rkolleryep you are right, that was a typo. your question about "if i am able to reproduce it on a clean install of the main branch" was gold, thank you! even though i did so already, it helped me to think things through again another time and do another round of testing - now i finally figured it out. some context, i am using the composer template by joachim for all of my testing in core and contrib. and i've dropped the database and installed the site again repeatedly the last view days and the problem persisted. so i first thought the problem might have something to do with the symlinking joachims template applies. so I did a clean install with just composer create-project targeting
main-dev@devand installed in addition only thecontent moderationandworkflowsmodules, basically the most minimal setup. that way, the problem hasn't turned up. did the same now with the joachim composer template install, dropped the db, reinstalled, and also only installed thecontent moderationandworkflowsmodules. the problem also not showed up. the sole difference to before on the joachim template install, i had more core modules in addition to the ones installed by the standard profile. and i was able to narrow it down to the root cause and i am able to reliably reproduce on the clean composer create project install as well as the joachim composer template after a fresh site install. in the following the steps to reproduce (and i guess best should be i'll create a follow up cuz this bug isnt directly related to this MR - i've just noticed it in the context of it, and it took quite a while to untwine it and get down to the root cause:ddev config --project-type=drupal12 --docroot=webddev composer create-project drupal/recommended-project:main-dev@devddev launchstandardprofileadmin/appearance, install the admin theme, and choose it as the administration themeadmin/modulesand installcontent moderationandworkflowsadmin/config/workflow/workflows/manage/editorial?destination=/admin/config/workflow/workflowsadd thearticlecontent type toContent typesin thethis workflow applies tosection and saveadmin/contentarticlenode with the titleCM & workflows V1, the statedraft, add something to the body, and saveCM & Workflows V2, change the status topublished, add some more text to the body to easier distinguish the two revisions, and hit save again.content/moderated, the title in the list saysCM & workflows V1, when you edit that node the title of the edited node also saysCM & workflows V1(basically you are editing the newly created third revision from the revert)admin/modulesalso installworkspacesmodule alongsideadmin/contentarticlenode with the titleCM, workflows, workspaces V1, the statedraft, add something to the body, and saveCM, workflows, workspaces V2, change status topublished. add some more text to the body to easier distinguish the two revisions, and hit save again.content/moderated, the title in the list saysCM, workflows, workspaces V1, when you edit that node the title of the edited node saysCM & workflows V2instead (you are now basically editing the published revision V2 instead of the intended/expected V1)Same effect if you also install the workspaces ui module. so it looks like the problem is located within the workspaces module that causes the problem if it is installed alongside the content moderation module.
p.s i am just uncertain if the followup should be filed against content moderation or the workspaces module?
Comment #116
acbramley commentedRe - #115 thank you for all that detail! Definitely sounds like something strange with workspaces (and potentially integration with that moderated content view). I would create an issue in workspaces.
Comment #117
benjifisher@acbramley, @rkoller:
The problem you have been discussing (Comments 110-116) may be a regression of #3037136: Make Workspaces and Content Moderation work together.
It adds to the confusion that, in reading the comments here, I keep confusing "workspaces" and "workflows". ;)
P.S. One of the issues linked to that one is #3541380: Node edit form always uses published revision when using content_moderation and workspaces, currently NR. I think that is exactly what you are looking for.
Comment #118
benjifisher@acbramley:
We looked at this issue at #3578994: Drupal Usability Meeting 2026-03-20, but we ran into the buggy behavior because we were using a test site that also had
workspacesenabled. So we did not get to a firm recommendation.My personal opinion (not the consensus of the meeting) is that it is confusing to add additional form elements to a confirmation form. I would rather keep it as a 2-step process: revert, then change the moderation state. What I would do to improve the process is add options to the drop buttons on the Revisions page: in addition to Delete, Revert, and Set ass current revision, add links for each available moderation state. Of course, the links would need either CSRF tokens or their own confirmation forms.
If you do not like that idea, then my second preference is to replace the confirmation form with a custom form: do not extend
ConfirmFormBaseand do not make it look like a confirmation form.Comment #119
opiMR 5696 does not apply properly on Drupal 11.3.7 ; Any clue ? thx
Comment #120
rkollerApologies, the writeup of the review for this issue took a "little" bit longer than expected, but this issue spiraled down into the rabbit hole of Content Moderation as a whole, and summarizing everything into a single, hopefully comprehensive, summary was quite challenging.
During our explorations we ran into a few more issues out of the scope for this issue. For example the problem we've encountered during our testing outlined in #2906568-115: Provide users with the option to select an appropriate moderation state when reverting to a previous revision turned out to be two fold. With Content Moderation and Workspaces module installed there is an already existing bug covered in #3541380: Node edit form always uses published revision when using content_moderation and workspaces, while with just Content Moderation installed the label for the default CTA on the Operations drop button is misleading which is covered now in #3580791: The edit button for a node with forward revision(s) on admin/content does not communicate editing the latest revision instead of the expected current revision.
Usability review
We discussed this issue for the first time at #3577382: Drupal Usability Meeting 2026-03-13. The link to the recording: https://www.youtube.com/watch?v=YYERRtLcNe4 . The attendees at the usability meeting were @pallavi singh3013, @rkoller, @simohell, and @worldlinemine.
While testing MR5696 we've identified a few noteworthy details:
h1is using a sort of lengthy conversational styled micro copy. It is rather hard to skim, because the information that is providing the sole context about which revision the node is getting reverted to, is at the very end of the heading. Strictly speaking it is not even communicated at all which node the confirmation page is about. In addition to that, even in the context of the revision list page with the other revisions around it is difficult to keep the different revisions apart. The sole indicators is the current revision as the anchor and the position of the revisions among each other. Stand alone, within the heading, the date and time is not that helpful to clearly and easily identify a revision, in particular for people with a small working memory - it is a rather abstract piece of information without any cue about the revision of which node. In summary this does not meet WCAG2.2 SC2.4.2 . The problem can be easily demonstrated by opening revert revision confirmation pages for several different nodes each in their own tab, you won't be able to tell the difference at all switching between those tabs.claroanddefault_adminon a mobile device, there is another detail to note (first claro then default admin):In
clarothe h1 is wrapped and the user is able to read the entire lengthy heading and deviate the context aka the node the revert is about from the breadcrumb. In contrast indefault_adminthe h1 remains a single line and the heading is getting truncated. That way the user is only presented with "Are you sure you want to revert to the revi..." and there is no proper breadcrumb trail available, there is only a "Back to site" link. That way the confirmation page becomes completely generic, due to the fact you have no information about context at all, neither the node nor the revision. The truncation indefault_adminalready got covered in #3570087: Page Title Ellipsis Accessibility Issue, while the wording of the h1 could be covered within this issue.h1. A date and time stamp, something likeFri, 17 Apr 2026 - 14:14, alone is also not a very helpful cue to contextualize the reverted revision. It would be helpful to have in support of the heading in the body of the confirmation form some more verbose information, "where i am at" aka what is the revision I am reverting from and "where I will be going to" aka what is the revision I reverting to.Revision moderation stateis referring to. During the meeting we've assumed it would reflect the state the revision "is coming from" and the select is setting the state the new revision is going to. While some of the attendees of the lean coffee table from the Drupal User Group Munich considered it the state of the new revision, and that its state could be altered with the select. @acbramley later confirmed that the attendees of the DUCMUC were right. But it illustrates that the microcopy and what it refers to is not clear at all but rather ambiguous and potentially misleading.I've continued the exploration the next few days to gain a better understanding of the content moderation problem space in general as it turned out we had quite a few misconceptions during the first meeting and it doesn't looked like it made sense to discuss the confirmation page in isolation. Therefore we've revisited this issue for a second time at #3578994: Drupal Usability Meeting 2026-03-20. The link to the recording: https://www.youtube.com/watch?v=JKzih7-X6CU . The attendees at the usability meeting were @benjifisher, @pallavi singh3013, @rkoller, @simohell, @the_g_bomb, and @worldlinemine.
At first we've discussed the content moderation module in general to get an idea about the bigger picture. #3578994-12: Drupal Usability Meeting 2026-03-20 contains a section with the rest of the problems we ran into that are out of the scope for this issue, but we will create dedicated issues for them soon.
In regard to the germinal question about the ability to set the moderation state within the confirmation step, one idea was to drop the informational
Revision moderation stateand only keep the select element - the default state could be the state the reverted revision will have while the user still has the ability to modify that default state to one of the states available to them. @benjifisher suggested another option during the meeting he already voiced in #2906568-118: Provide users with the option to select an appropriate moderation state when reverting to a previous revision. We've discussed the germinal question another time in today's meeting #3584127: Drupal Usability Meeting 2026-04-17 - Benji will add a summary with the outcome of that discussion.Comment #121
acbramley commentedThanks a lot @rkoller
Regarding the h1 - that is not being changed in this issue, if we want to discuss changes to that I think it should be done in a separate issue?
Comment #122
opiFor those like me who are struggling to apply patch on a regular Drupal 11.3.9, here is a modified patch from MR 5696. The Only changed part is about content_moderation.services.yml which is different between Drupal 11.x and the "main" branch (base branch for the MR).
Comment #123
nitinkumar_7 commentedHere's an updated patch. Adds a StateRevertValidation service with new per-state revert permissions (revert {workflow} revisions to {state}) independent of transition permissions — sites are unaffected until permissions are explicitly granted. The moderation state select is injected into the node revision revert form via the existing route subscriber. Currently Node-only with a @todo for #2350939. Needs usability review on the dropdown label/description text.