Adding & Removing Users on ProcessWire | OpsBlu Docs

Adding & Removing Users on ProcessWire

Adding & Removing Users on ProcessWire — setup, configuration, and best practices for ProcessWire.

ProcessWire treats users as pages in its page tree, stored under /processwire/access/users/. This page-based architecture means user management follows the same patterns as content management -- you can use the admin UI, the API, or template files to create, modify, and delete users.

How ProcessWire User Management Works

ProcessWire's user system is built on three core concepts:

  • Users -- Pages using the user template, stored under the users parent page
  • Roles -- Pages using the role template, stored under /processwire/access/roles/
  • Permissions -- Pages using the permission template, stored under /processwire/access/permissions/

Every user must have at least the guest role. The superuser role grants unrestricted access. Custom roles combine any set of permissions to create fine-grained access levels.

Adding Users via Admin UI

  1. Log in to the ProcessWire admin at https://your-site.com/processwire/
  2. Navigate to Access > Users in the top menu
  3. Click Add New in the page tree or use the Add New User button
  4. Fill in the required fields:
    • Name (username for login, lowercase, no spaces -- becomes the page name)
    • Email (used for password resets)
    • Password (minimum 6 characters by default, configurable)
  5. Under Roles, check the roles to assign:
    • guest (assigned automatically)
    • superuser (full admin access)
    • Any custom roles you have created
  6. Click Save

The user can immediately log in at https://your-site.com/processwire/ with their credentials.

Adding Users via the ProcessWire API

ProcessWire's API makes programmatic user creation straightforward:

<?php
// Create a new user via ProcessWire API
$u = new User();
$u->of(false); // Turn off output formatting
$u->name = 'jdeveloper';
$u->pass = 'SecurePass123!';
$u->email = 'jane@company.com';
$u->addRole('editor'); // Add a custom role
$u->save();

echo "Created user: {$u->name} (ID: {$u->id})";

Using the $users API variable:

<?php
// Alternative: using the $users API
$u = $users->add('jdeveloper');
$u->of(false);
$u->pass = 'SecurePass123!';
$u->email = 'jane@company.com';
$u->addRole('editor');
$u->save();

With custom fields (if your user template has additional fields):

<?php
$u = new User();
$u->of(false);
$u->name = 'jdeveloper';
$u->pass = 'SecurePass123!';
$u->email = 'jane@company.com';
$u->title = 'Jane Developer'; // Display name
$u->department = 'Engineering'; // Custom field
$u->phone = '555-0100';        // Custom field
$u->addRole('editor');
$u->addRole('page-editor');
$u->save();

Bulk User Management

Bulk Import via API Script

Create a template file or module for bulk user imports:

<?php
// bulk-import-users.php -- run via ProcessWire bootstrap
// Place in site root and access via CLI: php bulk-import-users.php

include('./index.php');

$csvFile = './user-import.csv';
$handle = fopen($csvFile, 'r');
$header = fgetcsv($handle); // name,email,password,role

$created = 0;
$skipped = 0;

while (($row = fgetcsv($handle)) !== false) {
    $data = array_combine($header, $row);

    // Skip if user already exists
    if ($users->get("name={$data['name']}")->id) {
        echo "Skipped (exists): {$data['name']}\n";
        $skipped++;
        continue;
    }

    $u = new User();
    $u->of(false);
    $u->name = $data['name'];
    $u->pass = $data['password'];
    $u->email = $data['email'];
    $u->addRole($data['role']);
    $u->save();

    echo "Created: {$data['name']} with role {$data['role']}\n";
    $created++;
}

fclose($handle);
echo "\nDone. Created: $created, Skipped: $skipped\n";

Bulk Role Assignment

<?php
// Assign a new role to all users who have the 'editor' role
$editors = $users->find("roles=editor");
foreach ($editors as $editor) {
    $editor->of(false);
    $editor->addRole('page-publisher');
    $editor->save();
    echo "Added page-publisher to: {$editor->name}\n";
}
echo "Updated {$editors->count()} users.\n";

Bulk Deactivation Script

<?php
// Deactivate users who haven't logged in within 90 days
$cutoff = time() - (90 * 86400);
$staleUsers = $users->find("login_timestamp<$cutoff, roles!=superuser");

foreach ($staleUsers as $u) {
    $u->of(false);
    $u->status = Page::statusUnpublished; // Effectively disables login
    $u->save();
    echo "Deactivated: {$u->name} (last login: " . date('Y-m-d', $u->login_timestamp) . ")\n";
}

Removing and Deactivating Users

Since users are pages, you can unpublish them to block login without deleting:

Via Admin UI:

  1. Navigate to Access > Users
  2. Click on the user
  3. In the Settings tab, change Status to Unpublished
  4. Click Save

Via API:

<?php
$u = $users->get('jdeveloper');
$u->of(false);
$u->status = Page::statusUnpublished;
$u->save();
echo "Deactivated: {$u->name}";

Unpublished users cannot log in. All their content and page edit history remains intact.

Removing Roles Without Deleting

<?php
$u = $users->get('jdeveloper');
$u->of(false);
$u->removeRole('editor');
$u->removeRole('page-editor');
// User retains 'guest' role only -- can log in but has no permissions
$u->save();

Permanent Deletion

Via Admin UI:

  1. Navigate to Access > Users
  2. Click on the user
  3. In the Settings tab, click Delete (or move to Trash)
  4. Confirm deletion

Via API:

<?php
$u = $users->get('jdeveloper');
if ($u->id && !$u->isSuperuser()) {
    $users->delete($u);
    echo "Deleted user: jdeveloper";
}

What happens to their content:

  • Pages created by the deleted user retain the created_users_id field pointing to the now-nonexistent user ID
  • Pages modified by the deleted user retain modified_users_id references
  • The admin page edit history (in the pages_access log) keeps the user ID as a number
  • File and image uploads remain in /site/assets/files/ regardless of user deletion
  • Comments or forum posts (if using community modules) retain the user reference but display as "Unknown User"

Reassign Content Before Deletion

<?php
$oldUser = $users->get('departing-user');
$newUser = $users->get('replacement-user');

// Find all pages created by the departing user
$pages = $pages->find("created_users_id={$oldUser->id}");
foreach ($pages as $p) {
    $p->of(false);
    $p->created_users_id = $newUser->id;
    $p->save();
}
echo "Reassigned {$pages->count()} pages from {$oldUser->name} to {$newUser->name}\n";

SSO and External Authentication

ProcessWire does not include built-in LDAP or SAML support, but its module system allows integration:

LoginRegisterPro Module (Third-Party)

The LoginRegisterPro module supports external authentication:

Custom LDAP Authentication Module

<?php
// site/modules/LdapAuth/LdapAuth.module
class LdapAuth extends WireData implements Module {

    public function init() {
        $this->addHookBefore('Session::authenticate', $this, 'ldapAuthenticate');
    }

    public function ldapAuthenticate(HookEvent $event) {
        $user = $event->arguments(0);
        $pass = $event->arguments(1);

        $ldapConn = ldap_connect('ldap://ldap.company.com');
        ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);

        $dn = "uid={$user->name},ou=People,dc=company,dc=com";
        if (@ldap_bind($ldapConn, $dn, $pass)) {
            // LDAP auth succeeded -- ensure PW user exists
            if (!$user->id) {
                $attrs = $this->getLdapAttrs($ldapConn, $dn);
                $u = new User();
                $u->of(false);
                $u->name = $user->name;
                $u->email = $attrs['mail'];
                $u->pass = $pass;
                $u->addRole('editor');
                $u->save();
            }
            $event->return = true;
            $event->replace = true;
        }
        ldap_unbind($ldapConn);
    }
}

Access Audit Checklist

  • Review all users under Access > Users, checking roles and last login dates
  • Use $users->find("roles=superuser") to audit who has full admin access
  • Check for users with status Unpublished that should be permanently deleted
  • Verify that the guest user has no roles beyond guest
  • Review custom user template fields for any sensitive data that should be encrypted
  • Audit the session_login_throttle table for brute-force attempts
  • Document all user provisioning in your change management system