New Addon - Moderation for collections

Think is something that is missing on Cockpit when comparing with other headless solutions, the possibility to define a status on the contents and therefore affect the api calls. Resuming, let’s imagine we want to work on a post that is already visible in live (Published state) and we want to save our changes but without having them visible. So using the addon we can save as a Draft and the API will still return the previous published version.

The Addon provides a new field type (Moderation) that enhances the collection form page with a new option:

image

More details on the project repo:

During the implementation I faced two challenges:

  1. Having the sidebar item positioned on top of the list, the way I did it is a bit hacky (via javascript), but would be interesting if we could have a weight value that could be used to define the order of the items, or a new event on the sidebar so we can manipulate the items
  2. Get the latest revision that have a field with a specific value, I’m hooking into the collections.filter.after and if the field is present and value is draft, I load the revisions and iterate until find the correct one. It works well, but not sure if it can cause performance troubles.

Feedback appreciated.

4 Likes

First of all, thanks for your work!

I have question regarding a specific use case, which you can hopefully answer for me.

I want to have a website where anonymous people can submit form data to be saved in cockpit via the api. but it would be necessary that all of this posts are created as drafts, which a moderator can later publish. is this possible with cockpit and your plugin?

thank you for your help!

all the best,
lukas

Hi @malua,

yes, you can set the moderation field to Draft when creating the entry, however since the API is exposed, the users may be able to manipulate the request and change the value. You can do the following to ensure that all API requests are saved as Draft.

Handle the trigger collections.save.before.<your_collection_name>:

// Include actions.
if (COCKPIT_API_REQUEST) {
  $app->on('collections.save.before.tests', function($name, &$entry, $isUpdate) {
    $entry['status'] = 'Draft';
  });
}

so any collection named tests that is created via the rest api, the status field will be Draft, so if you try to force the field value on your post request to other than Draft it will not have any impact:

{
	"data": {
		"title": "some title",
		"status": "Published"
	}
}

will result on status Draft

2 Likes

Thanks for the fast reply. This is exactly what I have been looking for!

For a project, I needed every change to a published page, to be stored as draft. With the info above, I created quickly the code below. It has to be improved a lot (works only for a given collection)

// new addon, bootstrap.php
<?php

// create a trigger
$app->on(
    // collections.save.before.<collectioname>
    'collections.save.before.page',
    function ($name, &$entry, $isUpdate) {
        // Get all revisions
        $revisions = $this->helper('revisions')->getList($entry['_id']);
        // latest revision is the first in the list
        $lastrevision = current($revisions);
        // If latest revision is a published one, our current changes are always in draft
        if ($lastrevision['data']['published'] == 'Published') {
            $entry['published'] = 'Draft';
        }
    }
);

I was in need for something similar like malua, just my users should submit their drafts (and only drafts) via the cockpit backend.
Just found out about cockpit yesterday but I managed to hack something together that works for me.

Those changes essentially check if a user group has moderation.forceDraft set to true in $var. If thats the case then this user wont get the entry-aside.php in the sidebar, they get a fake-entry-aside.php in their sidebars. This fake-version is missing the dropdown and defaults the moderation status to Draft.

I’m pretty certain that there is a way to change the default value even without a dropdown (and I’m sorry for abusing pauloamgomes code badly), but it does the trick for me.
Just thought I’d share it here if someone is in need of something similar and is even worse than me with cockpit.

Edit: just realized that the moderation status is still available via batch actions

Yeah, think that solution can be improved a bit, probably passing the possible states to the view.

@joshinat0r, updated the addon in the way you are describing:

Two new ACL’s are defined, so its possible to restrict a group to just create/update entries to draft (both on entry edit page and batch edit) - https://github.com/pauloamgomes/CockpitCMS-Moderation#permissions

The entry edit UI was also updated, so now by default when editing an existing entry the next state will be Draft by default:

1 Like

Great news, thank you very much. Much cleaner than my cruel attempt, updating the addon right now.

Edit: works just fine
Edit edit: Actually no, the get/{collectionName}-endpoint only contained the _id and children, all my fields were already missing when collections.find.after was iterating over the entries.
Removing the moderation.find.before hook brought back all my fields, not sure what it was supposed to fix, but it seems to fetch all my collections properly

Sorry about that, did an update, now it should not cause the error and also retrieve the correct fields for a draft entry.

2 Likes

Moderation now supports localization (thanks to @flommy) and scheduling - https://www.youtube.com/watch?v=TdhoThghRRY

Hi @pauloamgomes - I am looking at how to use the ACL permission for the moderation, I want to allow a group to unpublish entries. Where should I put this:

groups:
  MYGROUP:
    moderation:
      publish: true
      unpublish: true

I would like to be a global permission for all Collections.
Thanks