Jump to content

Hook to handle overriding access for the "Add New ▾" button (on the admin Page Tree)


Recommended Posts

I took Ryan's old Page Edit Per User module and modified it to:

  1. Allow users to assign access on pages they have edit access on (and pages they create)
  2. Check a field on the page, and current user, and make sure there is a matching value (ex: multiselect field on both the user account and the page)
  3. Allow adding pages so long as they have access to a parent page


  • Assign a role that has "page-edit" granted, but no templates are explicitly assigned to this access.
  • A multiselect text tag field is assigned to both the user profile template, and any templates of pages that I want the ability for access levels to be controlled. (example values of tags: HR, PR, IT, Administration, ...etc...)
  • When a user has a tag value assigned that matches a page's tag value, access to edit (and/or add) is granted.

It's mostly working (from the page tree) (I thought it was, the add button is visible, but the same error is displayed when clicking it); I have one instance where a parent isn't displaying the add button for children, but I'll look at that shortly... What definitely is not working: the "Add New" button is (surprisingly) properly displaying templates of pages that users have access to add based on my changes, but once a user tries to use that button, it displays the following error:


You don't have access to the template required to add pages here

This makes sense since the role doesn't assign any explicit templates, but now I'm trying to override that. I suspect once I fix this that there will be another area I'll also need to hook, but...

This message is part of ProcessPageAdd::___execute(). I tried to hook into `ProcessPageAdd::getAllowedTemplates` because in `execute`, it throws that error only if the template of the page to add isn't already defined in ProcessPageAdd::allowedTemplates. I might be going about this all wrong, but in the init() method of my adjusted PageEditPerUser, I have the following:

wire()->addHookBefore('ProcessPageAdd::getAllowedTemplates', $this, 'hookAllowedTemplates');

...and then the method:

 * ProcessPageAdd::getAllowedTemplates hook
public function hookAllowedTemplates($event) {
    // bd('hookAllowedTemplates');
    // bd($event, 'event');
    // bd($event->object, 'event->object');
    // bd($event->arguments(), 'event->arguments');
    $event->replace = true;
    $allowedTemplates = [];
    $allowedTemplates[input()->get->template_id] = templates()->get(input()->get->template_id);
    return $allowedTemplates;

One thing I struggle with, without others' examples, is what return value (and format) is expected from pre/post hooks. In this case I tried to completely replace the call to ProcessPageAdd::getAllowedTemplates because the value of $event->object->allowedTemplates in the post-hook is similar to a numerically indexed (by template ID) array of a template object (but contains a few more properties), but I still received the error as shown above.

(I know I'll need to do more checks on the values assigned in the above method call depending on scenario; right now my tests all have valid parent and template IDs, so I just want to get that working first.)

Any potential thoughts, either at what to look at, or where to further debug? (...or more code to share?)

Link to comment
Share on other sites

7 hours ago, BrendonKoz said:

I took Ryan's old Page Edit Per User module and modified it

Page Edit Per User takes the approach of first checking if PW says the user can edit a page, and if the answer is "yes" it returns early and doesn't apply any logic after that. So it only ever adds edit access and never removes it.

For your scenario I think you'll need to approach it differently and give the role the necessary permissions to edit, create and add children for all pages having the templates in question. Then in your hook remove the edit/add permission for individual pages according to your test for when the user is not allowed to edit or add children. You do that in hooks to Page::editable and Page:addable by setting the event return to false.

And in contrast to Page Edit Per User you'll only need to apply your hooks to users with a particular role. So your init method might look like this:

public function init() {
	if($this->wire()->user->hasRole('limited')) {
		$this->addHookAfter('Page::editable', $this, 'hookPageEditable');
		$this->addHookAfter('Page::addable', $this, 'hookPageAddable');


  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Create New...