Jump to content

Hiding uneditable pages from users


onjegolders

Recommended Posts

I only see that in the Admins Page-Tree:

Start

 - Admin

   - Access

     - Users

       admin

       guest

       user1

       ...

When I there go to "user1" no template is displayed, there are only Tabs for content and delete. So I find nothing where to put the field pagelist_hidden.

Under management/templates is no template therefor.

Ups - sorry - now I understand "you have to filter for system templates" - looking again in templates, I thought ALL templates are listend.

Ok, thanks, I try now...

  • Like 1
Link to comment
Share on other sites

I do not really get it to run.

I gave 3 users the access to edit their pages. I have added the pagelist_hidden field to each user, but only for one user I could select exact one page to hide and no other! 

Additional in the selection are only the subpages (News| News from user 1...2...3) and not other like "Blog" or "Contact".

It´s difficult to explain, the templates of the pages the user can edit are cloned, so all is the same, but only for user 2 I can select the one page of user 1 (News from user 1). If I select in addition the page that user 3 can edit, the selected page cannot be saved, after saving it just show again the page of user 2 is hidden. And this is ok, when logging in as user 2, the page of user 1 is not listend in admintree - so it should be.

But neither for user 1 nor user 3 I can hide something more, the selection-list is showing, but after saveing it is nothing select.

I have no more idea, I tried all I can do - it seems to be so simple: it should show the full admin-tree and I select per user what he can see and what not.

Have anybody got this run??

Link to comment
Share on other sites

I have it run!! :D

I'm not sure I can follow you completely and I have a difficult time understanding what is wrong with your setup and how much you understand what you're doing. :)

First, my setup is like this:

We need a multiple select page field you can select from all page in your site tree, that is..

- pagelist_hidden - a page field, multiple page (page array) checked, the setting is "Home" page as the parent and the inputtype is PageListSelectMultiple*

- No I attach this field to the user template (system template needs template filter set "Show system templates?" to show)

So now I can select and add pages that should be hidden on every user page, since user template now has this field. Now if you login with the user, page are not shown in page tree anymore.

This module does only this to filter those pages out on the ajax json response the admin page tree works with. It's more of a workaround and proof of concept / example module. It shows how it could be done. While this is simple, adding more features and configuration would go pretty complex and I'm not sure it's a route we should promote. Even just to reverse and add pages the user should see is a differnt thing considering a tree based structure. It's doable but maybe should be avoided.

I your case it sounds like every time a new user is added you need to do a lot and add the new pages to each user.

And you have templates for each user, but all the same setup? To get around the template based permissions I guess? I think it also could be avoided by using almost exact like module to add pages the user can edit and go with one set of templates.

I think there's also some examples or even a module by Ryan around.

https://github.com/ryancramerdesign/PageEditPerUser

http://processwire.com/talk/topic/2141-module-page-edit-per-user/

http://processwire.com/talk/topic/3051-page-edit-per-user-and-template-access-how-do-they-relate/

  • Like 2
Link to comment
Share on other sites

I'm not sure I can follow you completely and I have a difficult time understanding what is wrong with your setup and how much you understand what you're doing. :)

First, my setup is like this:

We need a multiple select page field you can select from all page in your site tree, that is..

- pagelist_hidden - a page field, multiple page (page array) checked, the setting is "Home" page as the parent and the inputtype is PageListSelectMultiple*

You have found the right words for me...  :)

I´ve tried everything except this setting: "Home" and no template selected.

It´s exactly that what I searched for and works great now!

While this is simple, adding more features and configuration would go pretty complex and I'm not sure it's a route we should promote. Even just to reverse and add pages the user should see is a differnt thing considering a tree based structure. It's doable but maybe should be avoided.

You are right, but sometimes it is very usefull. In my case there´s been some users access to put there content to the site. So there is no need to see a structure that could irritate them.

I your case it sounds like every time a new user is added you need to do a lot and add the new pages to each user.

And you have templates for each user, but all the same setup? To get around the template based permissions I guess? I think it also could be avoided by using almost exact like module to add pages the user can edit and go with one set of templates.

I know this. This was a workaround, because I don´t got it worked at the beginning and I wonder about to do so. But now there are the right settings. Of course, I just have one template now.

Thanks for the links! I tried the modul Page edit per user, maybe that´s a good solution in combination with pagelist_hidden.

Thank you very much for helping!!

Oh, I forgot - only one more thing in addition to "more features and configuration would go pretty complex"  :) 

Is it possible to make a selection like "Hidden all" ? This would make it easier to allow one page and hide all the others.

Link to comment
Share on other sites

  • 1 year later...

Hi everyone, I did a little thinking and coding on this issue last night. There is a gist on this post (https://processwire.com/talk/topic/8605-user-editsaddsmove-only-his-own-page/?p=84835) which hides uneditable pages, but be sure to read my comments in that post.

And based on my comment about the issues with "is editable" checks and the need to display non-editable parents to allow a user to access editable grandchildren, here is a much more comprehensive module that allows the ability to hide specific pages (and obviously their entire branch of children/grandchildren) based on the user role. It is based off my Page Protector module so it will look familiar to anyone who have used that.

It is just a first draft, so test carefully :)

It is attached here for now. Any thoughts?

AdminPageHider.zip

  • Like 9
Link to comment
Share on other sites

And based on my comment about the issues with "is editable" checks and the need to display non-editable parents to allow a user to access editable grandchildren, here is a much more comprehensive module that allows the ability to hide specific pages (and obviously their entire branch of children/grandchildren) based on the user role. It is based off my Page Protector module so it will look familiar to anyone who has used that.

Hi adrian,

thanks for that modul! I´ve installed it, but I don´t know if we mean the same.

In Tab of page your modul display

Hide this page
If checked, front-end viewing of this page will be limited to logged in users with one of the selected roles.

In my post https://processwire.com/talk/index.php?...&qpid=84829

I mean backend-viewing=hiding from admin tree, so if the user is logged in to edit his user-site he only should see in backend the page(s) he is allowed to edit (or create...). All other branches (except home) should be not even listed.

So let me ask you before I try - I just a little confused about the words "front-end viewing" ?

Link to comment
Share on other sites

Sorry about the "front-end viewing" text - that is a leftover from my Page Protector module, which this new module is based off. This module definitely only hides the page and its branch from the tree. Try it out.

Keep in mind though that with this module it doesn't have anything to do with whether a user has permission to edit a page or not - it is a manual way to determine the pages that aren't visible for a user role.

Did you take a look at the module at this gist: https://gist.github.com/adrianbj/e391e2e343c5620d0720

This should mostly do what you want in terms of hiding pages that aren't editable. I just haven't dealt with the issues of a page tree with many levels. It should work perfectly if there are only two levels below home.

Link to comment
Share on other sites

Keep in mind though that with this module it doesn't have anything to do with whether a user has permission to edit a page or not - it is a manual way to determine the pages that aren't visible for a user role.

Ok, I got it, this is a very good solution, if I want as superuser, that editors should not see some branches of my admin tree!

Did you take a look at the module at this gist: https://gist.github.com/adrianbj/e391e2e343c5620d0720

This should mostly do what you want in terms of hiding pages that aren't editable. I just haven't dealt with the issues of a page tree with many levels. It should work perfectly if there are only two levels below home.

I also tried this, but therefore all user pages has to get a different role.

Maybe my english is to poor to explain it exactly what I mean. Let me try it once more:

Remember the picture of the admin page tree I had.

In /visitenkarte/ are hundreds of pages each a vcard of a member, all that vcard pages have the same template with same role (in my case: only edit).

Each page name is equal to the members user name for login.

visitenkarte

...klipp

...benetton

...

...hundreds more

For example the page klip get a login with username klipp and password and he have the role editor with permission page-edit.

The same is for benetton and so on.

When klipp log in he should only see in Admin tree his vcard /klipp/ to edit and not be able to see all the other pages in tree!

This because, whenn there are hundreds of pages he must search through pagination until he find his page for edit.

Link to comment
Share on other sites

How about this:

https://gist.github.com/adrianbj/6fd1b770d9ce7a7252b6

It hides pages that don't match the user's name unless you are logged in as a superuser.

It is currently hardcoded to only check pages with parent named: visitenkarte

Does that work for you?

You are great!! This seems to work for me.

To hide all other branches under /home/ like visitenkarte, it´s correct to exclude this line, isn´t it?

if($c->parent->name != 'visitenkarte') continue;
  • Like 1
Link to comment
Share on other sites

Glad it works as you want!

If you remove that line, then you will hide all pages on your site, because there won't be any direct children of Home that match the name of the current user.

One other useful variation you might want to experiment with would be to replace:

if($c->name != $this->user->name) unset($json['children'][$key]);

with:

if($c->createdUser != $this->user) unset($json['children'][$key]);

which would hide pages that weren't created by the current logged in user.

  • Like 1
Link to comment
Share on other sites

One other useful variation you might want to experiment with would be to replace:

if($c->name != $this->user->name) unset($json['children'][$key]);

with:

if($c->createdUser != $this->user) unset($json['children'][$key]);

which would hide pages that weren't created by the current logged in user.

I will try it!

I must admit that I dont realy understand that hooks in module.

Is it possible to hide the pagination? Now user must turn the pagelist (only the numbers are displayed) to get his page.

And thanks a lot for your helping!

Link to comment
Share on other sites

I didn't think about the pagination issue.

I am not sure there is an easy fix for that with the current options for hooking into ProcessPageList

Just out of interest though, here is a new version that uses ProcessPageList::find as the hook - it simplifies some things quite a lot, but still doesn't fix the pagination issue :(

<?php

/**
 *
 *
 * ProcessWire 2.x
 * Copyright (C) 2010 by Ryan Cramer
 * Licensed under GNU/GPL v2, see LICENSE.TXT
 *
 * http://www.processwire.com
 * http://www.ryancramer.com
 *
 */

class HideOtherUserPages extends WireData implements Module {

    public static function getModuleInfo() {

        return array(
            'title' => 'HideOtherUserPages',
            'author' => 'Adrian Jones',
            'version' => 1,
            'singular' => true,
            'autoload' => true
            );
    }

    public function init() {
        // only add hook only if the render parameter is set
        // (as used by ProcessPageList)
        // or if superuser, also exit
        if(!isset($_GET['render']) || $this->user->isSuperuser()) return;
        $this->addHookAfter('ProcessPageList::find', $this, 'pageListHiddenPages');

    }

    public function pageListHiddenPages(HookEvent $event){

        $pages = $event->return;

        // make sure it's an ajax request
        if($this->config->ajax){
            // manipulate the json returned and remove any pages found from array
            foreach($pages as $p) {
                if($p->parent->name != 'visitenkarte') continue;
                if($p->name != $this->user->name) $pages->remove($p);
            }
            $event->return = $pages;
        }
    }
}
  • Like 2
Link to comment
Share on other sites

Here's another version that deals with the pagination issue you were getting. The problem is that it requires making a core method hookable that currently isn't.

Obviously modifying the core is not a good idea and I am not sure that Ryan will want to make numChildren hookable - seems like a weird thing to want to change. I feel like there is a better option to achieve this, but as a proof of concept, this does work. If it works as expected for you, maybe I'll see if we can get Ryan's thoughts on this.

So the first thing you need to do is go to wire/core/Page.php and make the numChildren function hookable by adding three underscores at the start, like:

public function ___numChildren($selector = null) {

Then use this module code:

<?php

/**
 *
 *
 * ProcessWire 2.x
 * Copyright (C) 2010 by Ryan Cramer
 * Licensed under GNU/GPL v2, see LICENSE.TXT
 *
 * http://www.processwire.com
 * http://www.ryancramer.com
 *
 */

class HideOtherUserPages extends WireData implements Module {

    public static function getModuleInfo() {

        return array(
            'title' => 'HideOtherUserPages',
            'author' => 'Adrian Jones',
            'version' => 1,
            'singular' => true,
            'autoload' => true
            );
    }



    public function init() {
        // only add hook only if the render parameter is set
        // (as used by ProcessPageList)
        // or if superuser, also exit
        //if(!isset($_GET['render']) || $this->user->isSuperuser()) return;
        if(!isset($_GET['render'])) return;
        $this->addHookAfter('ProcessPageList::find', $this, 'pageListHiddenPages');
        $this->addHookAfter('Page::numChildren', $this, 'pageListCountPages');

    }

    public function pageListCountPages(HookEvent $event){
        $page = $event->object;
        $i = 0;
        foreach($page->children() as $p) {
            if($page->name != 'visitenkarte') continue;
            if($p->name != $this->user->name) $i++;
        }
        $event->return = $event->return - $i;
    }

    public function pageListHiddenPages(HookEvent $event){
        $pages = $event->return;
        // make sure it's an ajax request
        if($this->config->ajax){
            // manipulate the json returned and remove any pages found from array
            foreach($pages as $p) {
                if($p->parent->name != 'visitenkarte') continue;
                if($p->name != $this->user->name) $pages->remove($p);
            }
            $event->return = $pages;
        }
    }
}
Link to comment
Share on other sites

Just out of interest though, here is a new version that uses ProcessPageList::find as the hook - it simplifies some things quite a lot, but still doesn't fix the pagination issue :(

Thanks for that, I tried it, I cannot see any difference?

So I have two lists of many User-Pages, now I take the second list out of the root under home in a subfolder (extra branche). One branche are pages with only one site called visitenkarte, the other branche is geschaefte with user-pages that have childs.

The templates in the branches are different and a same user can have edit permissions in the one branche and at same time edit and create permission in the second branche.

That works wonderful!

To do so I have added the name of second branche:

if($p->parent->name != 'visitenkarte' && $p->parent->name != 'geschaefte') continue;
Link to comment
Share on other sites

Here's another version that deals with the pagination issue you were getting. The problem is that it requires making a core method hookable that currently isn't.

Obviously modifying the core is not a good idea and I am not sure that Ryan will want to make numChildren hookable - seems like a weird thing to want to change. I feel like there is a better option to achieve this, but as a proof of concept, this does work. If it works as expected for you, maybe I'll see if we can get Ryan's thoughts on this.

So the first thing you need to do is go to wire/core/Page.php and make the numChildren function hookable by adding three underscores at the start, like:

public function ___numChildren($selector = null) {

Thank you very much again @adrian!

You are right, I´m sure there must be a better solution than modifying the core, but your work is great.

I dont tried it yet because I set the pagination in admin to a high it does not matter. the problem, this setting is over the hole site.

This are the first steps in my project, so, when I need pagination otherwhere, I´ll take your core-code because your code can switch off pagination only for a specific branche.

Here you can see in picture the running result:

21-01-2015%2022-10-04.jpg

Link to comment
Share on other sites

  • 2 weeks later...

I do not like to cross-post here from https://processwire.com/talk/topic/8605-user-editsaddsmove-only-his-own-page/ because it deals with another problem but as part of finding a solution to my problem by using the module of @adrian I discovered a problem when a user enters a name of a page he don’t have access to in the search field of the backend.

Example:
user 1 enters "Blau" in the search field.
user "Max Muster" also have a page named "Blau".
So, in the search results both pages are visible and can be edited by user 1. The search results looks like this:
 
s3Kpy2P.png

@guenter55 : maybe I’m missing something or I have a different configuration but how do you deal with that kind of (security) problem? 
 
Thomas
Link to comment
Share on other sites

  • 2 weeks later...
Example:
user 1 enters "Blau" in the search field.
user "Max Muster" also have a page named "Blau".
So, in the search results both pages are visible and can be edited by user 1. The search results looks like this:
 
s3Kpy2P.png

@guenter55 : maybe I’m missing something or I have a different configuration but how do you deal with that kind of (security) problem? 

 
Thomas

Hi @chuckymendoza

you are right, I see that problem too and it´s realy a problem.

I must think about. In my case it is a problem under the third path all others are secure.

/geschaefte/nailcult/firmendaten/ 	 
Angebote/News 	/geschaefte/nailcult/angebote-news/ 	 
Bildergalerie 	/geschaefte/nailcult/bildergalerie/ 	 
Avene Beratungstag 	/geschaefte/sternapotheke/angebote-news/avene-beratungstag/ 	bearbeiten
Neues Beitrag 6 	/geschaefte/schutzengelapotheke/angebote-news/neues-beitrag-6/ 	bearbeiten
Link to comment
Share on other sites

@guenter55 : maybe I’m missing something or I have a different configuration but how do you deal with that kind of (security) problem?
 
Thomas

Until I hav´nt found an other solution yet, - so sorry - a quick and dirty one: in ProcessPageSearch.module in 'protected function renderMatchesTable()' I changed the line

$row[] = $match->editable() ? "<a class='action' href='$editUrl'>" . $this->_('edit') . "</a>" : ' ';

to

$row[] = $match->editable() ? "<a class='action' href='#'>" . $this->_('edit') . "</a>" : ' ';

I killed the href, so if happens that the user find another users page with an edit button, he cannot follow at least

Link to comment
Share on other sites

Did you take a look at the module at this gist: https://gist.github.com/adrianbj/e391e2e343c5620d0720

This should mostly do what you want in terms of hiding pages that aren't editable. I just haven't dealt with the issues of a page tree with many levels. It should work perfectly if there are only two levels below home.

Hi adrian!

you write that modul (HideUneditablePages) is for not more than 2 levels, I think it´s the same for this modul 'HideOtherUserPages'. Please take a look at my post #42 again, you see in my case 'Angebote/News' is the third level and only this parent can have childrens (fourth level).

Just as @chuckymendoza wrote, when user search e.g. 'Produkte' (like in my picture) in adminsearching AND another user also have this in title, he get an edit button to the site he should not have access.This happens because it dont hide Other User Pages under level 3.

I tried to find a solution in 'public function pageListHiddenPages' but I don´t get it work.

Could you please help me?

Link to comment
Share on other sites

The problem is more of a user interface one, than a coding issue. If you have grandchildren that are editable, but children (their parent) that is editable, then you have to show that level anyway, or the page tree would become a mess :)

Have you tried this:

https://processwire.com/talk/topic/1176-hiding-uneditable-pages-from-users/?p=84916

That way you can hide the branches you want from the appropriate roles.

 

Alternatively, have you considered a custom admin page - either a process module, or one of these modules:

http://modules.proce...cess-dashboard/

http://modules.proce...n-custom-pages/

Link to comment
Share on other sites

Until I hav´nt found an other solution yet, - so sorry - a quick and dirty one: in ProcessPageSearch.module in 'protected function renderMatchesTable()' I changed the line

$row[] = $match->editable() ? "<a class='action' href='$editUrl'>" . $this->_('edit') . "</a>" : ' ';

to

$row[] = $match->editable() ? "<a class='action' href='#'>" . $this->_('edit') . "</a>" : ' ';

I killed the href, so if happens that the user find another users page with an edit button, he cannot follow at least

@chuckymendoza

above hack in core is´t sufficient because it ignores direct selecting in Ajax-Pop-Search result which takes me in foreign page editor.

In my case I not really need the adminsearch, so I create a new permission admin-search and give it to the role. In wire/modules/Process/ProcessPageSearch/ProcessPageSearch.module

I added in protected function render(PageArray $matches, $displaySelector) before

 return $out;

this code:

if(!$this->user->hasPermission('admin-search')) {
               $out = "*** Benutzer " . $this->user->name . ": diese Funktion ist gesperrt! ***"; 
          }

So when user has not in his role the permission 'admin-search' he get the message, that his is not allowed to use the search function in admin.

Maybe there is in future a feature in core to set permission on user-basis and/or role-basis but for now it is a solution for me.

@adrian:

I will make a copy of my work the next days, to try this. Now I am happy that it works with my little core hacks.

Knowing my solution doesn´t really consider the problem, I must also thinking about your sentence

If you have grandchildren that are editable, but children (their parent) that is editable, then you have to show that level anyway, or the page tree would become a mess :)

:) 

Link to comment
Share on other sites

  • 1 year later...
On 1/16/2015 at 11:42 PM, adrian said:

I didn't think about the pagination issue.

I am not sure there is an easy fix for that with the current options for hooking into ProcessPageList

Just out of interest though, here is a new version that uses ProcessPageList::find as the hook - it simplifies some things quite a lot, but still doesn't fix the pagination issue :(


<?php

/**
 *
 *
 * ProcessWire 2.x
 * Copyright (C) 2010 by Ryan Cramer
 * Licensed under GNU/GPL v2, see LICENSE.TXT
 *
 * http://www.processwire.com
 * http://www.ryancramer.com
 *
 */

class HideOtherUserPages extends WireData implements Module {

    public static function getModuleInfo() {

        return array(
            'title' => 'HideOtherUserPages',
            'author' => 'Adrian Jones',
            'version' => 1,
            'singular' => true,
            'autoload' => true
            );
    }

    public function init() {
        // only add hook only if the render parameter is set
        // (as used by ProcessPageList)
        // or if superuser, also exit
        if(!isset($_GET['render']) || $this->user->isSuperuser()) return;
        $this->addHookAfter('ProcessPageList::find', $this, 'pageListHiddenPages');

    }

    public function pageListHiddenPages(HookEvent $event){

        $pages = $event->return;

        // make sure it's an ajax request
        if($this->config->ajax){
            // manipulate the json returned and remove any pages found from array
            foreach($pages as $p) {
                if($p->parent->name != 'visitenkarte') continue;
                if($p->name != $this->user->name) $pages->remove($p);
            }
            $event->return = $pages;
        }
    }
}

I've used the above module to hide specific children pages with the template selector:

I've changed this line:

if($p->parent->name != 'visitenkarte') continue;

to this:

if($p->template->name != 'tour-content') continue;

and it partially works cause ProcessWire remembers what pages you click lately and if those pages have children and you reload the page that holds the page tree then all the children pages you want to hide are visible. Do you know how to fix this?

EDIT: Nevermind, no longer need to hide them but if you know how to fix that problem maybe you should share it for other users.

Link to comment
Share on other sites

  • 9 months later...

@adrian thank you, your module works great, and i have changed a statement after that everything works perfect, now can show only those pages to the logged in users which they have created. 

this :     if($c->createdUser != $this->user) unset($json['children'][$key]);

to this:

 if($c->createdUser->id != $this->user->id) unset($json['children'][$key]);

  • Like 1
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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...