Jump to content

Hiding uneditable pages from users


onjegolders

Recommended Posts

Is there anyway to hide uneditable pages from the end-user?

So that they only see the content that concerns them in order to avoid confusion.

I'm just finding that the templating has been refreshingly clear yet I'm struggling to replicate that in the backend, getting lost amongst the unpublished, hidden and user privileges. I'm also unsure if it's possible to let users edit a page's content without them having access to that page's settings?

In my head, if they can't edit something they shouldn't be able to see it.

Sorry for all the newbie posts :)

  • Like 1
Link to comment
Share on other sites

You have to create a new editor role and assign it to this user (maybe you did this already). Then go to the template, and in "Access" do as on the attached screenshot

edit: sorry, i completely misunderstood your question...

post-88-0-04182100-1334012722_thumb.png

Edited by diogo
Link to comment
Share on other sites

You have to create a new editor role and assign it to this user (maybe you did this already). Then go to the template, and in "Access" do as on the attached screenshot

Thanks Diogo, so setting "view page" to no - means they can't see it in the editor? They can still see it live?

Also is it possible to remove the user's possibility to change settings on a page? I don't really want them changing templates etc, just adding content.

Link to comment
Share on other sites

Thanks Diogo, so setting "view page" to no - means they can't see it in the editor? They can still see it live?

Also is it possible to remove the user's possibility to change settings on a page? I don't really want them changing templates etc, just adding content.

Setting "View page" to no means they can't access it at all. I am not sure if I understand what you are looking for: you don't want clients see pages in the admin that they cannot edit? I don't think that is possible currently and I found it rather confusing. Our clients love the "bird eye" view that full site tree gives them, it is helpful for them to know where all pages are, regarding if they can edit that page or not. If they don't have access to certain page, then it won't be shown in page tree either.

There is permission required for changing template, so just edit the role and disable "Change templates on pages" permission.

Link to comment
Share on other sites

Is there anyway to hide uneditable pages from the end-user?

It would be trivial for a module to hook into the PageList and avoid listing pages that the user can't edit. But it's not something that I recommend in a tree-based hierarchy because access can change at any branch. The PageList is meant to show everything the user can view. The context of the hierarchy is generally important everywhere in ProcessWire, whether the user can edit a given branch or not.

I'm also unsure if it's possible to let users edit a page's content without them having access to that page's settings?

There are permissions in the user's role that control their access to all the relevant items from the settings tab. Another route you can take is to lock down the allowed parents and templates from any given template's "family" tab. But that is structure control rather than access control, as it applies to everyone. However, it's the one I find most handy to ensure clients (and myself!) aren't adding or moving pages around where they shouldn't.

Link to comment
Share on other sites

It would be trivial for a module to hook into the PageList and avoid listing pages that the user can't edit. But it's not something that I recommend in a tree-based hierarchy because access can change at any branch. The PageList is meant to show everything the user can view. The context of the hierarchy is generally important everywhere in ProcessWire, whether the user can edit a given branch or not.

There are permissions in the user's role that control their access to all the relevant items from the settings tab. Another route you can take is to lock down the allowed parents and templates from any given template's "family" tab. But that is structure control rather than access control, as it applies to everyone. However, it's the one I find most handy to ensure clients (and myself!) aren't adding or moving pages around where they shouldn't.

I think you're right, changing the template's family seems to be the best option. Think that's why a continued site walkthrough would be so useful as it would show such instances where you want to lock down parents.

I think front-end it's great that PW gets out of the way and just offers 'helpers' back-end can sometimes be a bit harder to get the head around!

Link to comment
Share on other sites

There's a lot in PW (like the Template > Family tab) that is really useful when you get things going, but not really necessary when getting started. It's one of those things that you tend to find once the need comes up. I'd used ProcessWire for years without a lot of this stuff. So it's always a bit of a battle balancing simplicity vs. power. I think it will be good for these tutorials to outline what's essential [to get things started] and what's not. One of the problems I had with EE years ago is that I would get lost in it's endless configuration screens, and not really know what I needed and what I didn't. I'm writing this here so I won't forget when it comes time to expand upon the tutorials. :)

  • Like 1
Link to comment
Share on other sites

There's a lot in PW (like the Template > Family tab) that is really useful when you get things going, but not really necessary when getting started. It's one of those things that you tend to find once the need comes up. I'd used ProcessWire for years without a lot of this stuff. So it's always a bit of a battle balancing simplicity vs. power. I think it will be good for these tutorials to outline what's essential [to get things started] and what's not. One of the problems I had with EE years ago is that I would get lost in it's endless configuration screens, and not really know what I needed and what I didn't. I'm writing this here so I won't forget when it comes time to expand upon the tutorials. :)

Good plan!

I know what you mean about EE's configuration. Having used it for 6 months, it seems like second nature for me to set up channels and field groups and then link the two but I guess in the beginning there was initial confusion.

I'd be quite interested to know what your workflow was like when starting a project in PW:

Assuming you already have a static site, would you start adding all your templates, then all the fields, or vice versa, or back and forth between templates, fields and pages and then do you deal with permissions all at the end?

Link to comment
Share on other sites

Regarding workflow: the default profile is pretty much always my starting point. It's rare that I don't end up repurposing the fields and templates that are already there to start building things out. Likewise, I usually end up just renaming (as necessary) and repopulating the pages that are already in the default profile. Then I will start adding new fields, followed by templates, specific to the needs of the site. While I try to determine most of the templates/fields that I'll need ahead of time, I will continue adding fields and templates throughout the entire development process as necessary to make the site do what I want it to.

Most larger PW sites are pretty relational and make good use of Page references. But this is also the part that I think is most important to outline when it comes to workflow. This part is quite a bit different from other systems, but has major advantages. I try to make my selectable Page references part of the site's structure, if at all possible. For example, on tripsite.com, every bike tour has a "country" page reference field, and those countries are useful in the site's overall structure (Netherlands in this case):

http://www.tripsite.com/countries/netherlands/

In other cases, page references might not fit as part of the site's general structure, so I'll have a /tools/ section in the site where they live. Though it's easy enough to make them function as pages, so I figure why not. :) Here are a few examples (they are all using the same template):

Multi-page reference field "months" (April in this case):

http://www.tripsite.com/tools/months/april/

Multi-page reference field "tour_types" (Guided in this case):

http://www.tripsite.com/tools/tour-types/guided/

Page reference field "difficulty" (Difficult in this case):

http://www.tripsite.com/tools/difficulty/difficult/

The template used on those pages is not much more than this:

$tours = $pages->find("template=tour, {$page->parent->name}=$page, limit=10"); 
foreach($tours as $tour) {
   // output the tour
}

Admittedly, most of my projects are rebuilding existing sites, so I usually have some (or a lot) of data to migrate to the new site. This becomes a major component of the development workflow, so I figured I should mention it here. After I've setup the necessary fields and templates (and usually before front-end development), I'll work on bringing in the new data. If it's a relatively simple conversion job, I might use the ImportPagesCSV module. But most jobs require some markup replacement, character set conversion or other things, so I'll build my own import script. This is where I like to bootstrap PW from a command line PHP script. Here's a simple example:

/import-airports.php

#!/usr/bin/php
<?php
require("./index.php"); // bootstrap PW
$fp = fopen("./airports.csv", "r");

while(false !== ($data = fgetcsv($fp))) {

   $page = new Page();
   $page->template = 'airport';
   $page->parent = '/building-types/airports/';
   $page->title = $data[0];
   $page->location = $data[1];
   $page->year = $data[2];

   $architectName = wire('sanitizer')->pageName($data[3], true);
   $architect = wire('pages')->get("/architects/$architectName/"); 

   if(!$architect->id) {
       $architect = new Page();
       $architect->template = 'architect';
       $architect->parent = '/architects/';
       $architect->title = $data[3];
       $architect->name = $architectName; 
       $architect->save();    
   }

   $page->architect = $architect; 
   $page->save();

   echo "\nCreated page: {$page->url}";
}

Once I've got a lot of data to work with in the system, I'll start doing front-end development: creating the template files, markup, css and anything else necessary to handle the output for the site. The files from the basic profile either get used as a starting point, or replaced completely at this point.

These are my main workflow components I can think of, but let me know if there are any specific areas you'd like more detail on or can think of anything I've missed.

  • Like 6
Link to comment
Share on other sites

Regarding workflow: the default profile is pretty much always my starting point. It's rare that I don't end up repurposing the fields and templates that are already there to start building things out. Likewise, I usually end up just renaming (as necessary) and repopulating the pages that are already in the default profile. Then I will start adding new fields, followed by templates, specific to the needs of the site. While I try to determine most of the templates/fields that I'll need ahead of time, I will continue adding fields and templates throughout the entire development process as necessary to make the site do what I want it to.

Most larger PW sites are pretty relational and make good use of Page references. But this is also the part that I think is most important to outline when it comes to workflow. This part is quite a bit different from other systems, but has major advantages. I try to make my selectable Page references part of the site's structure, if at all possible. For example, on tripsite.com, every bike tour has a "country" page reference field, and those countries are useful in the site's overall structure (Netherlands in this case):

http://www.tripsite....es/netherlands/

In other cases, page references might not fit as part of the site's general structure, so I'll have a /tools/ section in the site where they live. Though it's easy enough to make them function as pages, so I figure why not. :) Here are a few examples (they are all using the same template):

Multi-page reference field "months" (April in this case):

http://www.tripsite....s/months/april/

Multi-page reference field "tour_types" (Guided in this case):

http://www.tripsite....r-types/guided/

Page reference field "difficulty" (Difficult in this case):

http://www.tripsite....ulty/difficult/

The template used on those pages is not much more than this:

$tours = $pages->find("template=tour, {$page->parent->name}=$page, limit=10");
foreach($tours as $tour) {
// output the tour
}

Admittedly, most of my projects are rebuilding existing sites, so I usually have some (or a lot) of data to migrate to the new site. This becomes a major component of the development workflow, so I figured I should mention it here. After I've setup the necessary fields and templates (and usually before front-end development), I'll work on bringing in the new data. If it's a relatively simple conversion job, I might use the ImportPagesCSV module. But most jobs require some markup replacement, character set conversion or other things, so I'll build my own import script. This is where I like to bootstrap PW from a command line PHP script. Here's a simple example:

/import-airports.php

#!/usr/bin/php
<?php
require("./index.php"); // bootstrap PW
$fp = fopen("./airports.csv", "r");

while(false !== ($data = fgetcsv($fp))) {

$page = new Page();
$page->template = 'airport';
$page->parent = '/building-types/airports/';
$page->title = $data[0];
$page->location = $data[1];
$page->year = $data[2];

$architectName = wire('sanitizer')->pageName($data[3], true);
$architect = wire('pages')->get("/architects/$architectName/");

if(!$architect->id) {
	$architect = new Page();
	$architect->template = 'architect';
	$architect->parent = '/architects/';
	$architect->title = $data[3];
	$architect->name = $architectName;
	$architect->save();	
}

$page->architect = $architect;
$page->save();

echo "\nCreated page: {$page->url}";
}

Once I've got a lot of data to work with in the system, I'll start doing front-end development: creating the template files, markup, css and anything else necessary to handle the output for the site. The files from the basic profile either get used as a starting point, or replaced completely at this point.

These are my main workflow components I can think of, but let me know if there are any specific areas you'd like more detail on or can think of anything I've missed.

Thanks Ryan, the level of detail really helps me understand better.

Out of interest, what would your 'tree' look like?

Country as an example is a page with children and on a particular tour, you'd select the country to reference to?

I keep finding in these early days that I'll get lost between templates and pages, I'll create a sub page and then realize that I have to go back into one or two templates and change the family settings, but I'm sure I'll pick it up.

I'm also a bit unsure still over unpublished/hidden.

I think a massive strength of PW over something like EE is the control over relationships and also reordering, which was an incredibly difficult process.

I guess I found EE was very good for my needs as most of my site's editors will never really be creating new main pages, just adding subpages or 'content' as I think of it. They add a new article, my templates populate the blog index and view page. They enter a new event, it would be pulled into homepage and events page etc.

So I find a lot of my effort has been going into 'closing down' the parent pages. I think when set up though, as you show with your tripsite example (great site by the way) it becomes very powerful to relate things to each other.

Thanks once again for being so helpful, it makes such a big difference!

Link to comment
Share on other sites

  • 1 year later...

It would be trivial for a module to hook into the PageList and avoid listing pages that the user can't edit. But it's not something that I recommend in a tree-based hierarchy because access can change at any branch. The PageList is meant to show everything the user can view. The context of the hierarchy is generally important everywhere in ProcessWire, whether the user can edit a given branch or not.

Hi Ryan,

While I hoped it would be trivial for me to setup a module that hides Pages in the admin that are not editable by the user, I've not been able to get it to work.

What method specifically would be the one I'd want to hook into?  I've tried ProcessPageListRender, ProcessPageList and even Page methods.  Would be a huge help if you could point me in the right direction.

Are there any other resources you'd recommend for Module development?  I've looked into Captain Hook, but wondering if there's anything else you think would help someone who's struggling a bit to grasp the basics (where do the event properties come from, how to get references to pages, etc.).

Thanks a lot.

Link to comment
Share on other sites

The hook you'd want to use would probably be Page::viewable. However, hiding pages that a user can't edit just doesn't work in a tree hierarchy, because how then would a user get to the pages that they can edit? A better strategy would be to figure out exactly what you don't want the user to see in the admin tree, whether it is branch of a tree, a specific page, or all pages using a specific template. And take into account the fact that nothing under the page(s) will be editable since the user won't be able to navigate to them. 

public function init() {
  $this->addHookAfter('Page::viewable', $this, 'hookPageViewable'); 
}

public function hookPageViewable(HookEvent $event) {
  if(!$event->return) return; // page already not viewable
  $page = $event->arguments(0);
  if($page->template == 'my-private-template') $event->return = false;
}
  • Like 2
Link to comment
Share on other sites

Hi Ryan,

Thanks for the reply.  Your approach makes sense, though I'll probably flip it on it's head and show only a specific template rather than hide all the others.

The issue I'm coming up against is that I don't seem to be able to get any information out of the event getting passed in to the function that's called when the hook is hit.

I trace out count($event->arguments) and get 0. I'm extending the WireData class, but have also tried extending Process.  

Trying to understand why I would get no arguments with my event and ideally how I could figure out what data should get passed with events to hook handling functions.

Thanks again.

Link to comment
Share on other sites

Are there any other resources you'd recommend for Module development?  I've looked into Captain Hook, but wondering if there's anything else you think would help someone who's struggling a bit to grasp the basics (where do the event properties come from, how to get references to pages, etc.).

Just a quick tip: check out source for HookEvent.php. It should / could clarify things a bit, especially the comments there. Wiki article for module development isn't complete yet, but still worth taking a look at too :)

Link to comment
Share on other sites

Thanks for the tip @teppo.  I've looked into the HookEvent source, and although helpful I'm still having issues.

Among that strange things I've noticed is this:  when I add

$this->message($event->object->name);

as the only line in the hook function, the output I get is the name of each of the top level pages in the PW admin.  So, 'page', 'page', 'setup','template','field', etc.

While all of the examples I've seen use $event->object to get a reference to non-admin pages, mine seems to be returning only admin pages.  Maybe there's a conflict with another non-core PW module?  I've got the following other modules installed:

  • FieldtypeColorPicker
  • ProcessSelectorTest
  • HelperFieldLinks
  • ImportPagesCSV
  • MarkupSitemapXML
  • ModulesQuickFilter
  • PageReferencesTab
  • ProcessBatcher
  • ProcessRedirects

Would really appreciate help from anyone who has an idea of what might be going on.

Thanks!

Link to comment
Share on other sites

OK, here's the entire module.  Thanks for any suggestions.

class HidePagesNotEditable extends WireData implements Module {

	/**
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them
	 *
	 * @return array
	 *
	 */
	public static function getModuleInfo() {

		return array(
			'title' => 'Hide Pages Not Editable',
			'version' => 100,
			'summary' => 'Hides Pages in the admin when the user does not have edtiable access',
			'autoload' => true
			);
	}

	public function init() {
		$this->addHookAfter('Page::viewable', $this, 'showOnlyEditable');
	}

	public function showOnlyEditable(HookEvent $event) {
		// $event->return = false; // causes redireect loop
		// if($event->return) return; // seems to have no effect
		// $this->message(var_dump($event->arguments)); // returns array(0) {}
		$this->message($event->object->name);

	}

}
Link to comment
Share on other sites

Ok since you hook Page::viewable every page in PW will be somehow affected, even admin pages as they are also just pages.

So the message with $event->object->name is the admin pages rendered in the admin template. I'd guess it's the navigation. But since the ProcessPageList module is ajax driven you won't see any messages from there.

$event->arguments is nothing there I think, as the important with these page access hooks is the $event->return value.

So you would do set it to false or true

$event->return = false; // page won't be viewable

All the viewable hook does is define if a page is viewable or throw an 404.

In case of the admin page tree the page will still be visible and only have no -view- action button. That's all.

If you really want to hide pages in the admin I'm with Ryan, but see that there's cases where it would be nice to hide pages from users and keep a branch hidden from them.

I already stumbled and tried very hard 1-2 years ago, but realized it's not easy as there's no obvious hooks available where needed and it's done with ajax and there's some things to consider, didn't really bother.

Now after thinking for some time and try error I found an easy way to just remove pages from the page list tree. The trick is to modify the JSON output that goes with the ajax response, convert it to an array and

Long story short here's an example module for those interested. I used a pagelist_hidden page field added to the user template to define pages that are hidden for a user. Of course there could be endless configuration possibilities, with roles and what not, but don't want to go any further and maybe someone else finds this useful or as a start for a new module.

If Ryan reads this and is still with me. Would you consider adding some hooks to ProcessPageList.module? Or do you think the JSON manipulation is a good way? 

Most likely there would have to be some additional take care to make those pages also not editable. Those page will still be accessible manually through admin url. Such a module shouldn't be used to hide pages for access restriction, and it's only and best suited for hiding "private" branches in the admin, or functional pages that can't be in the /Admin/ branch for some reasons.

  • Like 6
Link to comment
Share on other sites

Hi Soma,

Thanks so much for your detailed response.  Glad I wasn't going crazy thinking it was harder than it seems.  I'm going to try your method and will post back here with results.

To give some context, here's the background on my use case:  the site is for a large hardware store chain for which each store manager should be able to edit the info on their store's information page.  Showing them the full page tree would unnecessarily complicate the process for what is almost surely a non-technical audience.

While not a must have, it will cut down on support requests from the store managers who get lost in the page tree while looking for their store.

Thanks again Soma.

Link to comment
Share on other sites

  • 3 weeks later...

Long story short here's an example module for those interested. I used a pagelist_hidden page field added to the user template to define pages that are hidden for a user. Of course there could be endless configuration possibilities, with roles and what not, but don't want to go any further and maybe someone else finds this useful or as a start for a new module.

Hi Soma,,

I tried this module, but I don´t get it work - maybe I´m using it wrong.

I made a new field pagelist_hidden and I can add it to templates and select pages, so that works. But what exactly should I do?

My Admin/Pages now:

Start | view

 - Blog | view

 - News | view

    - News from user 1 | view edit

    - News from user 2 | view

    - News from user 3 | view

 - Contact | view

 - ....

What I want is:

 

User 1 should have access to "News form user 1" and only see in this admin-tree his own page to edit!

Start | view

 - News | view

    - News from user 1  | view edit

I.e. all the user-pages "News from 1" ...2...3 have there own template and normaly it works correct. When user 1 is logged in he can edit his page and in the admin-tree the others pages only have the "view".

But there are many other pages and the user 1 should not be confused of that.

What I tried was that I gave the template to "News from user 1" the pagelist_hidden field and in the page I selected some pages to hide them, but nothing effect. I thougt there must be something like "this user should not see these pages".

Please what I am doing wrong?

Thanks for helping!

Link to comment
Share on other sites

I think the page field should be added to the user template and not the news template. As per description the page field is to define page that are invisiblevto the user.

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...