Adding and Removing Users in Craft CMS | OpsBlu Docs

Adding and Removing Users in Craft CMS

Complete guide to creating, inviting, managing, suspending, and deleting user accounts in Craft CMS via Control Panel and programmatically.

Comprehensive guide to adding, inviting, managing, suspending, and deleting user accounts in Craft CMS through the Control Panel and programmatically.

Adding Users via Control Panel

Method 1: Create User Directly

  1. Navigate to Users in the Control Panel
  2. Click + New user button
  3. Fill in user details:
    • Email - Required, must be unique
    • Username - Optional, auto-generated from email if blank
    • First Name / Last Name - Optional
    • Password - Set initial password or send activation email
    • Photo - Optional profile picture
    • User Groups - Assign to one or more groups
    • Custom Fields - Fill in any custom user fields
  4. Click Create user

Method 2: Send Activation Email

For users who should set their own password:

  1. Create new user as above
  2. Enable Send an activation email
  3. User receives email with link to set password
  4. User activates account and sets password

User Status Options

When creating users:

  • Active - User can log in immediately
  • Pending - Awaiting activation
  • Suspended - Cannot log in
  • Locked - Locked due to failed login attempts

Adding Users Programmatically

Create User via PHP

<?php

use craft\elements\User;

// Create new user
$user = new User();

// Set user properties
$user->username = 'johndoe';
$user->email = 'john@example.com';
$user->firstName = 'John';
$user->lastName = 'Doe';

// Set password
$user->newPassword = 'SecurePassword123!';

// Assign to groups
$user->setGroupIds([1, 3]); // Group IDs

// Set custom field values
$user->setFieldValues([
    'bio' => 'Software developer and writer',
    'company' => 'Acme Inc',
    'newsletterOptIn' => true,
]);

// Save user
if (Craft::$app->elements->saveElement($user)) {
    echo 'User created successfully';
} else {
    print_r($user->getErrors());
}

Create User via Twig (Front-End Registration)

{# templates/account/register.twig #}

<form method="post" accept-charset="UTF-8">
  {{ csrfInput() }}
  {{ actionInput('users/save-user') }}
  {{ redirectInput('account/welcome') }}

  <h2>Create Account</h2>

  {# Username #}
  <label for="username">Username</label>
  <input type="text"
         name="username"
         id="username"
         required
         value="{{ user.username ?? '' }}">

  {# Email #}
  <label for="email">Email</label>
  <input type="email"
         name="email"
         id="email"
         required
         value="{{ user.email ?? '' }}">

  {# Password #}
  <label for="password">Password</label>
  <input type="password"
         name="password"
         id="password"
         required
         minlength="12">

  {# First/Last Name #}
  <label for="firstName">First Name</label>
  <input type="text"
         name="firstName"
         id="firstName"
         value="{{ user.firstName ?? '' }}">

  <label for="lastName">Last Name</label>
  <input type="text"
         name="lastName"
         id="lastName"
         value="{{ user.lastName ?? '' }}">

  {# Custom Fields #}
  <label for="fields-bio">Bio</label>
  <textarea name="fields[bio]" id="fields-bio">{{ user.bio ?? '' }}</textarea>

  <label>
    <input type="checkbox" name="fields[newsletterOptIn]" value="1">
    Subscribe to newsletter
  </label>

  {# Submit #}
  <button type="submit">Create Account</button>
</form>

{# Display validation errors #}
{% if user is defined and user.hasErrors() %}
  <div class="errors">
    <h3>Please fix the following errors:</h3>
    <ul>
      {% for attribute, errors in user.getErrors() %}
        {% for error in errors %}
          <li>{{ error }}</li>
        {% endfor %}
      {% endfor %}
    </ul>
  </div>
{% endif %}

Inviting Users

Send Invitation Email

<?php

use craft\elements\User;

// Create user
$user = new User();
$user->username = 'janedoe';
$user->email = 'jane@example.com';
$user->firstName = 'Jane';
$user->lastName = 'Doe';
$user->pending = true; // Mark as pending

// Save user
if (Craft::$app->elements->saveElement($user)) {
    // Send activation email
    Craft::$app->users->sendActivationEmail($user);

    echo 'Invitation sent to ' . $user->email;
}

Custom Invitation Template

Create custom activation email template:

{# templates/_emails/user-activation.twig #}

Hi {{ user.friendlyName }},

Welcome to {{ siteName }}! Please click the link below to activate your account and set your password:

{{ activationUrl }}

This link will expire in 24 hours.

If you did not request this account, please ignore this email.

Best regards,
The {{ siteName }} Team

Configure in config/app.php:

return [
    'components' => [
        'mailer' => [
            'messageConfig' => [
                'from' => ['noreply@example.com' => 'Site Name'],
            ],
            'templates' => [
                'activate-account' => [
                    'subject' => 'Activate your {{ siteName }} account',
                    'htmlBody' => '_emails/user-activation.twig',
                ],
            ],
        ],
    ],
];

Bulk User Import

Import Users from CSV

<?php

use craft\elements\User;
use craft\helpers\StringHelper;

// Read CSV file
$csvFile = '/path/to/users.csv';
$rows = array_map('str_getcsv', file($csvFile));
$header = array_shift($rows);

$successCount = 0;
$errorCount = 0;

foreach ($rows as $row) {
    $data = array_combine($header, $row);

    // Create user
    $user = new User();
    $user->email = $data['email'];
    $user->username = $data['username'] ?? StringHelper::toLowerCase($data['email']);
    $user->firstName = $data['first_name'] ?? '';
    $user->lastName = $data['last_name'] ?? '';
    $user->pending = true;

    // Assign to default group
    $user->setGroupIds([1]); // "Members" group

    // Save user
    if (Craft::$app->elements->saveElement($user)) {
        // Send activation email
        Craft::$app->users->sendActivationEmail($user);
        $successCount++;
    } else {
        echo "Error importing {$data['email']}: " . implode(', ', $user->getFirstErrors()) . "\n";
        $errorCount++;
    }
}

echo "Import complete: {$successCount} successful, {$errorCount} failed\n";

CSV format:

email,username,first_name,last_name
john@example.com,johndoe,John,Doe
jane@example.com,janedoe,Jane,Doe

Editing Users

Update User via Control Panel

  1. Navigate to Users
  2. Click on user to edit
  3. Modify user details
  4. Update user groups
  5. Change custom field values
  6. Click Save

Update User Programmatically

<?php

use craft\elements\User;

// Get user by ID
$user = User::find()->id(123)->one();

if ($user) {
    // Update properties
    $user->firstName = 'Updated';
    $user->lastName = 'Name';

    // Update custom fields
    $user->setFieldValue('bio', 'Updated bio text');
    $user->setFieldValue('company', 'New Company');

    // Add to additional group
    $currentGroups = $user->getGroups()->ids();
    $currentGroups[] = 5; // Add group ID 5
    $user->setGroupIds($currentGroups);

    // Save changes
    if (Craft::$app->elements->saveElement($user)) {
        echo 'User updated successfully';
    } else {
        print_r($user->getErrors());
    }
}

User Self-Update (Front-End)

{# templates/account/profile.twig #}

{% requireLogin %}

<form method="post" accept-charset="UTF-8" enctype="multipart/form-data">
  {{ csrfInput() }}
  {{ actionInput('users/save-user') }}
  {{ redirectInput('account/profile') }}

  <input type="hidden" name="userId" value="{{ currentUser.id }}">

  <h2>Edit Profile</h2>

  {# Email #}
  <label for="email">Email</label>
  <input type="email"
         name="email"
         id="email"
         value="{{ currentUser.email }}"
         required>

  {# Name #}
  <label for="firstName">First Name</label>
  <input type="text"
         name="firstName"
         id="firstName"
         value="{{ currentUser.firstName }}">

  <label for="lastName">Last Name</label>
  <input type="text"
         name="lastName"
         id="lastName"
         value="{{ currentUser.lastName }}">

  {# Photo Upload #}
  <label for="photo">Profile Photo</label>
  {% if currentUser.photo %}
    <img src="{{ currentUser.photo.getUrl({ width: 100 }) }}" width="100">
    <label>
      <input type="checkbox" name="deletePhoto" value="1">
      Delete current photo
    </label>
  {% endif %}
  <input type="file" name="photo" id="photo" accept="image/*">

  {# Custom Fields #}
  <label for="fields-bio">Bio</label>
  <textarea name="fields[bio]" id="fields-bio">{{ currentUser.bio }}</textarea>

  <label for="fields-company">Company</label>
  <input type="text"
         name="fields[company]"
         id="fields-company"
         value="{{ currentUser.company }}">

  <label>
    <input type="checkbox"
           name="fields[newsletterOptIn]"
           value="1"
           {{ currentUser.newsletterOptIn ? 'checked' }}>
    Receive newsletter
  </label>

  <button type="submit">Save Changes</button>
</form>

{# Success message #}
{% if craft.app.session.hasFlash('notice') %}
  <div class="success">
    {{ craft.app.session.getFlash('notice') }}
  </div>
{% endif %}

{# Error messages #}
{% if currentUser.hasErrors() %}
  <div class="errors">
    <ul>
      {% for error in currentUser.getErrors() %}
        <li>{{ error }}</li>
      {% endfor %}
    </ul>
  </div>
{% endif %}

Suspending Users

Suspend User via Control Panel

  1. Navigate to Users
  2. Click on user
  3. Change Status to Suspended
  4. Click Save

Suspend User Programmatically

<?php

use craft\elements\User;

// Get user
$user = User::find()->id(123)->one();

if ($user) {
    // Suspend user
    $user->suspended = true;

    // Save
    if (Craft::$app->elements->saveElement($user)) {
        echo 'User suspended';

        // Optionally log out user immediately
        Craft::$app->users->destroyUserSession($user);
    }
}

Unsuspend User

<?php

// Unsuspend user
$user->suspended = false;

if (Craft::$app->elements->saveElement($user)) {
    echo 'User unsuspended';

    // Optionally send notification
    $message = Craft::$app->mailer->compose()
        ->setTo($user->email)
        ->setSubject('Your account has been reactivated')
        ->setHtmlBody('Your account access has been restored.')
        ->send();
}

Deleting Users

Delete User via Control Panel

  1. Navigate to Users
  2. Select user(s) to delete
  3. Click Delete button
  4. Confirm deletion
  5. Choose what to do with their content:
    • Delete their content - Permanently remove
    • Transfer to another user - Reassign content
    • Leave content as-is - Keep content, remove authorship

Soft delete keeps user data but prevents login:

<?php

use craft\elements\User;

// Get user
$user = User::find()->id(123)->one();

if ($user) {
    // Method 1: Suspend user
    $user->suspended = true;
    Craft::$app->elements->saveElement($user);

    // Method 2: Set to inactive
    $user->enabled = false;
    Craft::$app->elements->saveElement($user);

    // Method 3: Mark as archived (Craft 4+)
    $user->archived = true;
    Craft::$app->elements->saveElement($user);
}

Hard Delete

Permanently delete user and optionally transfer content:

<?php

use craft\elements\User;

// Get user
$user = User::find()->id(123)->one();

if ($user) {
    // Option 1: Delete user and their content
    $deleted = Craft::$app->elements->deleteElement($user);

    // Option 2: Transfer content to another user first
    $transferToUser = User::find()->id(456)->one();

    if ($transferToUser) {
        // Transfer authored entries
        $entries = craft\elements\Entry::find()
            ->authorId($user->id)
            ->all();

        foreach ($entries as $entry) {
            $entry->authorId = $transferToUser->id;
            Craft::$app->elements->saveElement($entry);
        }

        // Transfer uploaded assets
        $assets = craft\elements\Asset::find()
            ->uploaderId($user->id)
            ->all();

        foreach ($assets as $asset) {
            $asset->uploaderId = $transferToUser->id;
            Craft::$app->elements->saveElement($asset);
        }

        // Then delete user
        Craft::$app->elements->deleteElement($user);
    }
}

Bulk User Management

Bulk Suspend Users

<?php

use craft\elements\User;

// Get users to suspend
$users = User::find()
    ->lastLoginDate('< ' . date('Y-m-d', strtotime('-1 year')))
    ->all();

foreach ($users as $user) {
    $user->suspended = true;

    if (Craft::$app->elements->saveElement($user)) {
        echo "Suspended: {$user->email}\n";
    }
}

Bulk Delete Inactive Users

<?php

use craft\elements\User;

// Get users who never logged in and are older than 30 days
$users = User::find()
    ->lastLoginDate(':empty:')
    ->dateCreated('< ' . date('Y-m-d', strtotime('-30 days')))
    ->all();

foreach ($users as $user) {
    // Don't delete admins
    if (!$user->admin) {
        if (Craft::$app->elements->deleteElement($user)) {
            echo "Deleted: {$user->email}\n";
        }
    }
}

Bulk Group Assignment

<?php

use craft\elements\User;

// Add all users with specific custom field to a group
$users = User::find()
    ->newsletterOptIn(true)
    ->all();

$newsletterGroupId = 5;

foreach ($users as $user) {
    $currentGroups = $user->getGroups()->ids();

    if (!in_array($newsletterGroupId, $currentGroups)) {
        $currentGroups[] = $newsletterGroupId;
        $user->setGroupIds($currentGroups);

        if (Craft::$app->elements->saveElement($user)) {
            echo "Added {$user->email} to newsletter group\n";
        }
    }
}

User Cleanup Tasks

Clean Up Pending Users

Remove users who never activated their account:

<?php

use craft\elements\User;

// Delete pending users older than 7 days
$pendingUsers = User::find()
    ->status(User::STATUS_PENDING)
    ->dateCreated('< ' . date('Y-m-d', strtotime('-7 days')))
    ->all();

foreach ($pendingUsers as $user) {
    if (Craft::$app->elements->deleteElement($user)) {
        echo "Deleted pending user: {$user->email}\n";
    }
}

Lock Inactive Users

Lock users who haven't logged in for a long time:

<?php

use craft\elements\User;

// Lock users inactive for 6 months
$inactiveUsers = User::find()
    ->lastLoginDate('< ' . date('Y-m-d', strtotime('-6 months')))
    ->status(User::STATUS_ACTIVE)
    ->all();

foreach ($inactiveUsers as $user) {
    if (!$user->admin) {
        $user->locked = true;

        if (Craft::$app->elements->saveElement($user)) {
            // Send notification
            $message = Craft::$app->mailer->compose()
                ->setTo($user->email)
                ->setSubject('Account locked due to inactivity')
                ->setHtmlBody('Your account has been locked. Contact us to reactivate.')
                ->send();

            echo "Locked: {$user->email}\n";
        }
    }
}

Best Practices

1. Always Validate User Input

// Validate before saving
if (!$user->validate()) {
    foreach ($user->getErrors() as $attribute => $errors) {
        echo "{$attribute}: " . implode(', ', $errors) . "\n";
    }
}

2. Send Notifications

Notify users of account changes:

// User suspended
Craft::$app->mailer->compose()
    ->setTo($user->email)
    ->setSubject('Account suspended')
    ->setHtmlBody('Your account has been suspended...')
    ->send();

3. Log User Changes

use craft\helpers\App;

// Log user creation
Craft::info(
    "User created: {$user->email} by " . Craft::$app->user->identity->email,
    'users'
);

// Log user deletion
Craft::info(
    "User deleted: {$user->email} by " . Craft::$app->user->identity->email,
    'users'
);

4. Handle Content Ownership

Always consider what to do with user content:

  • Transfer entries to another author
  • Transfer assets to another uploader
  • Archive content
  • Delete content

5. Maintain Audit Trail

Keep records of user management actions:

// Store in custom table or log file
$auditLog = [
    'action' => 'user_deleted',
    'user_id' => $user->id,
    'user_email' => $user->email,
    'performed_by' => Craft::$app->user->identity->id,
    'timestamp' => date('Y-m-d H:i:s'),
    'reason' => 'Inactive for 1 year',
];

Console Commands

Create User via CLI

# Create user interactively
php craft users/create

# Create user with parameters
php craft users/create \
  --email="user@example.com" \
  --username="username" \
  --password="SecurePassword123!" \
  --admin

# Send activation email
php craft users/send-activation-email user@example.com

Delete User via CLI

# Delete user by email
php craft users/delete user@example.com

# Delete user by ID
php craft users/delete --user-id=123

Next Steps

Resources