Restrict page publishing to certain user roles

Hi there,

I have a pretty standard scenario: I will have users with an editor role that create pages and then – once ready – change the pages’ status from draft to unlisted (which I renamed to “Queued for Review”).

Now I also have users with the review role. Those should now be able to review those pages and publish them.

However, I cannot figure out how to disallow publishing for editors while at the same time allow publishing for reviewers. How could I achieve this?

Thanks!
trych

You can set role based permissions in your user role blueprints: Permissions | Kirby CMS
The page options can also be set/overwritten on a per page level in the page blueprints.

In your case, the relevant option is the changeStatus option.

But this can only be set to true/false, right?

Because I do want the users with editor role to be able to change the page status to unlisted, so they need to be allowed to change a status, I just don’t want to them to be able to change it to published as well.

So, unless I am misunderstanding you, the changeStatus option in the user role blueprint does not really solve my problem, I think.

True, there is no option for changeStatusToListed or so. You can probably prevent status changes through a page model with a modified changeStatus method, but it won’t hide/disable the option in the menu.

Or use a page.changeStatus:before hook.

In both cases, the user will only see an error message when executing the action.

Ok, I am a bit surprised that there is no simpler way to do this, as I assume this is a fairly common scenario.

I wonder if this could be solved by a piece of custom Panel JS? But then the JS would need to have information on the user somehow and there seems to be no indication in the rendered HTML which user is currently logged in.

Ok, I solved this now with some Panel CSS and JS. Here’s how I did it:

In my blueprints, I added a help text to some section that shows the role of the currently logged in user:

mysection:
  type: pages
  help: "{{ kirby.user.role.name }}"

Then I created a panel CSS that makes this help footer invisible (but still readable to JS) and that hides the third entry in the status change panel. Also, it adds a style that makes this entry visible again if my panel pages main body has a data-role attribute of admin or reviewer:

.k-collection-footer, .k-collection-help, .k-collection-help p {
  visibility: hidden;
  height: 0;
  margin: 0;
}

.k-field-name-status li:nth-child(3) {
  display: none;
}

body[data-role = "admin"] .k-field-name-status li:nth-child(3),
body[data-role = "reviewer"] .k-field-name-status li:nth-child(3) {
  display: block;
}

Lastly I added some Panel JS that detects the hidden footer and its content and assigns that content as a data attribute to the panel page’s body tag. As soon as the body tag gets a data-role attribute of admin or reviewer, the “Published” option becomes available again in the status change panel, otherwise it doesn’t:

const userRoleInterval = setInterval(() => {
  const userP = document.querySelector('.k-section-name-draftprojects footer p');

  if(userP) {

    if(userP.textContent === "admin" || userP.textContent === "reviewer") {
      document.body.setAttribute("data-role", userP.textContent);
    }

    clearInterval(userRoleInterval);
  }
}, 10);

Note: This needs to use the setInterval() method as Vue will take a moment to make the panel page available. If anyone knows how to detect the Vue lifecycle hooks from the outside via Vanilla JS, please let me know. Also, this setup works only if there is a single help text on the page. Otherwise you would maybe need to prefix the help text with a specific prefix that JS could detect.

I think I will open a feature request for a dedicated changeStatusToListed permission, as my solution is more hacky then I would like to (and is of course not secure, but for my specific project it’s sufficient).

What about a hook that changes page status to either draft or unlisted when the page is edited?
This way the editors don’t even need to change the status by themselves and you can disable it completely.

I mean: if what the editors write needs approval, you would have to do this anyway, otherwise they could just edit already public pages and add their dick pics there.

That’s a good point, but I think I could actually solve that with a hook that automatically changes the template once the page gets set to published, so that editors cannot change it then anymore.

That part I don’t quite understand. How would the system know when it’s supposed to change it to unlisted? The editors can work on an article for some time and then at some point decide to put it up for review and therefor change the status manually. I don’t see how a hook could do this automatically.

I just meant the hook changes the published pages either to “draft” or “unlisted” (you as a programmer chose one now, both have valid arguments) when an editor changes a currently published page, like if they see a typo or something.

Editors would then only work on drafts and signal “readiness to be published” not with the status, but in another way; like a checkbox or something. You can then either show that checkbox in the panel section via a query in the info property (like, point to a model function or a page method to format it nicely). Or you use a “pagesdisplay” section (plugin) to show ready pages in section that query for “ready” pages.
Or you use the hook to change the status to unlisted when the checkbox is ticked.

Ah, ok, now I get it. However, I think in my specific case I would actually like to change the template of published pages to something that the editors cannot change anymore themselves.

The checkbox is also a good idea, will keep that in mind. For now, my hacky CSS solution seems to work well enough for this project.

Thanks!