Jump to content

ProcessWire User System Update


ryan
 Share

Recommended Posts

You may have noticed when using PW2 that when working in Admin > Access > Roles, it gives you a message about "currently in development..." That's because the user/role system was kind of a temporary solution until we had something more concrete. This post is to give you an update on what's in the new user system and tell you how it works. The user system is currently in production, but close to being finished and already being tested in a few places.

Users are now Pages


In this new system, users, roles and permissions are now all a form of pages, each with their own group of fields. This means they can be managed just like pages both from the admin as well as from the API. It also means that you can add any fields you want to users (and roles and permissions if you have the need). You can add fields in the same manner that you add them to your own templates.

The other benefit to this system is that it's now just as scalable as the pages system (given that users are now a form of pages). Any code that you write to find, iterate or manipulate pages is compatible with users.

While you can use the $pages API var to access user system variables, the system also provides $users, $roles and $permissions API vars that only operate exclusively on their specific type. These API vars also provide some consistency/compatibility with the existing API vars that were in the previous user system.

Access is now managed by Templates rather than Pages


I was never that crazy about the way ProcessWire's access was managed by turning roles ON or OFF on any given page. The role settings were inherited through the hierarchy, which was necessary, but also complex. While it could be powerful, these were the main problems I had with it:

1. On a 5,000 page site, there were 5,000 possible places to define access. Granted, you might only define access in a couple places in your site and let the rest inherit that access, but you had to be very disciplined and careful to take advantage of the power it offered. The scope of possibilities here isn't particularly client-friendly for when you hand over the keys to the site.

2. Since access was inherited, you would typically define it on a parent page that had dozens/hundreds/thousands of children, rather than defining it individually on those children. The problem here is that if you want to assign edit access to those children, you would also be giving edit access to the parent... something you may not want to do.

3. The existing system presented some challenges in determining a user's access to a page before it was actually loaded from the database. So when you did a broad $pages->find(), the results needed to be post-filtered (by you) if you didn't want to include pages the user couldn't view. I know this behavior may be desirable in many instances, but ideally it should be optional.

4. Like setting up templates and fields, I've always viewed access configuration as being something more appropriate as part of the site's setup that I would perform, rather than something that my clients would make decisions about in their daily page adding/editing activities. Managing this at the page-level never seemed like an ideal fit.

What's different in the new access system?

The new system solves the 4 issues mentioned above. In this system, access is managed with templates rather than pages. So on your 5,000 page site with 10 templates, you now have 10 places where you can manage access rather than 5,000, but with the same amount of power and control. In addition, you don't have to manage it in every template if you don't want to -- templates don't manage access unless you check a box to tell it to. So pages using templates that don't manage access simply inherit their access. That access is inherited through the page's parents until it finds one with a template defining access.

Lets use the PW default site as an example. Access is defined on the "home" template. That access is inherited by the other pages in the site because we set the other two templates ("page" and "sitemap") not to manage access. And then there is the "admin" template that defines it's own access. So all pages under /processwire/ are controlled with the access settings assigned to that "admin" template. To word it another way, access for all of the PW default site is defined on the "home" and "admin" templates.

I've attached a few screenshots so that you can see what this looks like. Two other things to notice in these screenshots:

1. You can now specify your own custom redirect URL to send a user to when they don't have access.

2. You can set pages to NOT be searchable when the user doesn't have access. This will prevent them from appearing in $pages->find() operations (for example). Previously you had to do your own post-filtering.

How roles and permissions work


ProcessWire's user system is still considered an RBAC (Role-based-access-control system).  Any given user can have one or more roles. Roles can be thought of like "groups of users", and a user may belong to multiple groups. All users, including anonymous visitors have the "guest" role. Individual permissions are assigned to these roles. A user inherits ALL of the permissions assigned to all of their roles. The "guest" role typically only has "page-view" permission.

When it comes to page-specific permissions (like "page-view", "page-edit" and so on), both the user and the page (via it's template) must have the same roles assigned before those permissions become applicable. This is best demonstrated with an example:

Lets say you've got a "guest" role and a "member" role. Both roles just have one permission, which is "page-view". Then lets say you've got a page at "/members/" using a template called "members". When editing the "members" template, you've checked the "member" role, but not the "guest" role. Even though both roles have the same "page-view" permission, only users with the "member" role will be able to view the "/members/" page. Likewise, any pages in your site using templates that don't have the "guest" role will be invisible to anonymous site users.

You can now add your own site-specific permissions


You could add your own permissions in the old system, but you had to do it via the API. In the new system, you can add your own permissions right from the admin, should you want to. So lets say that you wanted to add your own permission that would determine whether user could submit comments on a page. You would go to Admin > Access > Permissions and "add permission" and call it something like "submit-comments". Then in your template, you could check if the user has that permission:

<?php
if($user->hasPermission('submit-comments')) {
   // draw form or save submission
}

That snippet just asks the question "Does the current user have this permission?" It doesn't ask if the current user has the permission on a specific page. Should you want to verify the permission for a specific page, you would add the $page you want to check to the hasPermission call:

<?php
if($user->hasPermission('submit-comments', $page)) {
   // draw form or save submission
}

Users, Pages and Usage in the API


While the user system now uses pages for it's types, the user, role and permission pages aren't directly "viewable" as pages on your site, like other pages are. You certainly could make them viewable without too much trouble, but I don't see the point (technically they are pages in the admin). They are based on pages purely for the flexibility and scalability in managing user data. So if you wanted to create a page where a user could "view" their profile, for instance, you'd so it with your own template:

<?php
echo "<p>Welcome {$user->name}</p>!";
echo "<p>Your email address is: {$user->email}</p>";
echo "<p>Your favorite color is: {$user->favorite_color}</p>";

Or lets say that you wanted to list a all the users in the system that had the role "member" and wanted to sort them by name, and list 25 per page:

<?php
$role = $roles->get("member"); 
$members = $users->find("roles=$role, sort=name, limit=25"); 
echo $members->render();

There really is no difference between the above example and what you would do with pages except that we're using $roles and $users API vars rather than $pages. You could also use $pages, but you'd have to specify the "user" and "role" templates to make it work:

<?php
$role = $pages->get("name=member, template=role"); 
$members = $pages->find("template=user, roles=$role, sort=name, limit=25"); 
echo $members->render();

post-1-132614277376_thumb.png

post-1-132614277401_thumb.png

post-1-132614277432_thumb.png

Link to comment
Share on other sites

I've posted the 2.1 development version on GitHub if anyone wants to take a look at it. The features in this version are those described above. I don't recommend building any production sites with this, because this is very much a work in progress and things may yet change. However, if anyone is interested in testing I appreciate any feedback you have. Currently you can only do a fresh install of this version, because the upgrade script is not yet ready (i.e. don't attempt to upgrade an existing PW 2.0 site with this version).

http://github.com/ryancramerdesign/P21

Thanks,

Ryan

Link to comment
Share on other sites

  • 4 months later...

Ryan, i miss something or the new user system is not yet implemented in 2.1?  ???

It is implemented. Probably you just miss the "Filter" on top of the templates page, where you can let it "Show system templates". After that just add more fields to your "user" template.

Link to comment
Share on other sites

We'll support adding more user templates in the near future. Though if you don't mind changing a few lines in the core, I can show you how to do it now. But either way, you can always create your own new templates and use a page reference to associate them to a user. Another option is to add the fields that all users need to your user template, and use your front end logic to show and populate only the relevant fields for a given type of user. I would suggest using roles as a way to assign user types.

Also keep in mind that PW's user system in it's default state is for access control. Since it doesn't produce markup for your site, it's not a ready-to-go solution for a turnkey social site. The framework for it is there, but not the interface. So if you are building a site where non-administrative users are managing profiles and such, then PW will happily handle the data, but you'll still have to write the markup and use the API like you would in any other part of your site.

Link to comment
Share on other sites

Thanks as always, yes i'm writing the markup for user management in frontend and i have a question about this:

i'm testing the frontend user profile and right now i can easily manage "my profile" page as  /profile (i created a blank page in the tree) showing all my fields and a form for edit my profile, now i also want to browsing other user profiles, not mine, but i need something in the url to get the user data like an id or the name like /username. How can i do that? Because if i write something like /profile/username PW gets 404 because the page doesn't exist in the tree...

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
 Share

  • Recently Browsing   0 members

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