Textpattern CMS manages users through its built-in admin panel. It uses a simple but effective role-based system with six privilege levels. Users are stored in the txp_users table in the MySQL/MariaDB database.
How Textpattern User Management Works
Textpattern has six built-in privilege levels, ordered from least to most access:
| Level | Role | Capabilities |
|---|---|---|
| 0 | None | Account exists but no access (effectively disabled) |
| 1 | Publisher | Full admin access, can manage users and site settings |
| 2 | Managing Editor | Can manage most content, sections, categories |
| 3 | Copy Editor | Can edit and publish articles by any author |
| 4 | Staff Writer | Can create and edit own articles, upload images |
| 5 | Freelancer | Can create articles (draft only, cannot publish) |
| 6 | Designer | Can edit pages, forms, and stylesheets |
There is no concept of "groups" -- each user has exactly one privilege level.
Adding Users via Admin Panel
- Log in to the Textpattern admin at
https://your-site.com/textpattern/ - Navigate to Admin > Users
- The "Add new author" form appears at the top of the page
- Fill in the fields:
- Real name (display name)
- Login name (username, must be unique)
- Email address
- Privileges -- select from the dropdown (Publisher, Managing Editor, etc.)
- Click Save new author
Textpattern generates a random password and emails it to the new user's email address. The user can then change their password after logging in.
Adding Users via Database
For automated provisioning or when the admin panel is inaccessible:
-- Insert a new user directly into the database
-- Password must be hashed with Textpattern's algorithm (bcrypt as of Txp 4.7+)
INSERT INTO txp_users (
name, pass, RealName, email, privs, last_access, nonce
) VALUES (
'jdeveloper',
-- Generate bcrypt hash: password_hash('SecurePass123!', PASSWORD_BCRYPT)
'$2y$10$examplehashhere',
'Jane Developer',
'jane@company.com',
4, -- Staff Writer privilege level
NOW(),
MD5(CONCAT(RAND(), NOW()))
);
Using PHP to generate the password hash:
<?php
// Generate a Textpattern-compatible password hash
$password = 'SecurePass123!';
$hash = password_hash($password, PASSWORD_BCRYPT);
echo "INSERT hash: $hash\n";
Adding Users via Textpattern API (Plugin)
The smd_user_manager plugin extends Textpattern with advanced user management:
<!-- Using smd_user_manager plugin tags in a Textpattern page -->
<txp:smd_user_manager_register
form="registration_form"
privileges="5"
confirm_email="1"
/>
<!-- Registration form -->
<txp:smd_user_manager_register_form>
<p>
<label for="real_name">Full Name</label>
<input type="text" name="RealName" id="real_name" required />
</p>
<p>
<label for="login_name">Username</label>
<input type="text" name="name" id="login_name" required />
</p>
<p>
<label for="email">Email</label>
<input type="email" name="email" id="email" required />
</p>
<p>
<label for="password">Password</label>
<input type="password" name="pass" id="password" required />
</p>
<button type="submit">Register</button>
</txp:smd_user_manager_register_form>
Bulk User Management
Bulk Import via SQL
-- Bulk insert multiple users
-- Pre-generate bcrypt hashes for each password
INSERT INTO txp_users (name, pass, RealName, email, privs, last_access, nonce)
VALUES
('editor1', '$2y$10$hash1...', 'Editor One', 'editor1@company.com', 3, NOW(), MD5(RAND())),
('editor2', '$2y$10$hash2...', 'Editor Two', 'editor2@company.com', 3, NOW(), MD5(RAND())),
('writer1', '$2y$10$hash3...', 'Writer One', 'writer1@company.com', 4, NOW(), MD5(RAND())),
('writer2', '$2y$10$hash4...', 'Writer Two', 'writer2@company.com', 4, NOW(), MD5(RAND())),
('freelancer1', '$2y$10$hash5...', 'Freelancer One', 'freelancer1@agency.com', 5, NOW(), MD5(RAND()));
Bulk Import Script (PHP)
<?php
// bulk-import-users.php
// Run from the Textpattern root directory
define('txpath', __DIR__ . '/textpattern');
require_once txpath . '/config.php';
require_once txpath . '/lib/txplib_db.php';
$users = [
['name' => 'editor1', 'real' => 'Editor One', 'email' => 'editor1@company.com', 'privs' => 3],
['name' => 'editor2', 'real' => 'Editor Two', 'email' => 'editor2@company.com', 'privs' => 3],
['name' => 'writer1', 'real' => 'Writer One', 'email' => 'writer1@company.com', 'privs' => 4],
['name' => 'designer1', 'real' => 'Designer One', 'email' => 'designer1@company.com', 'privs' => 6],
];
foreach ($users as $u) {
$tempPass = bin2hex(random_bytes(8));
$hash = password_hash($tempPass, PASSWORD_BCRYPT);
$nonce = md5(uniqid(mt_rand(), true));
$result = safe_insert('txp_users', "
name = '" . doSlash($u['name']) . "',
pass = '" . doSlash($hash) . "',
RealName = '" . doSlash($u['real']) . "',
email = '" . doSlash($u['email']) . "',
privs = " . intval($u['privs']) . ",
nonce = '" . doSlash($nonce) . "'
");
if ($result) {
echo "Created: {$u['name']} ({$u['email']}) - Temp password: $tempPass\n";
} else {
echo "Failed: {$u['name']}\n";
}
}
Bulk Privilege Update
-- Promote all Staff Writers to Copy Editors
UPDATE txp_users SET privs = 3 WHERE privs = 4;
-- Demote all Managing Editors to Copy Editors (except specific users)
UPDATE txp_users
SET privs = 3
WHERE privs = 2
AND name NOT IN ('chief_editor', 'content_lead');
Removing and Deactivating Users
Deactivation (Recommended)
Set the user's privilege level to None (0) to block access without deleting:
- Navigate to Admin > Users
- Find the user in the list
- Change their Privileges dropdown to None
- Click Save
Via SQL:
-- Deactivate a user by setting privileges to 0
UPDATE txp_users SET privs = 0 WHERE name = 'jdeveloper';
-- Deactivate multiple users
UPDATE txp_users SET privs = 0 WHERE name IN ('contractor1', 'contractor2', 'old_editor');
Users with privilege level 0 cannot log in to the admin panel. Their account and all associated content remain intact.
Permanent Deletion
Via Admin Panel:
- Navigate to Admin > Users
- Check the box next to the user(s) to delete
- Select Delete from the "With selected..." dropdown at the bottom
- Click Go
- Confirm the deletion
Via SQL:
-- Delete a single user
DELETE FROM txp_users WHERE name = 'jdeveloper';
What happens to their content:
- Articles authored by the deleted user remain in the
textpatterntable with theAuthorIDcolumn still referencing the deleted username as a string - Articles display with the author name intact on the front end (the name is stored as text, not a foreign key)
- Images uploaded by the user remain in the
txp_imagetable and on disk - File uploads remain in
txp_file - The articles list in the admin may show the old username but clicking it yields no author filter results
- Comments by site visitors are unaffected (stored separately)
Reassign Articles Before Deletion
-- Reassign all articles from the departing user to another author
UPDATE textpattern
SET AuthorID = 'replacement_editor'
WHERE AuthorID = 'departing_user';
-- Verify
SELECT AuthorID, COUNT(*) AS article_count
FROM textpattern
WHERE AuthorID IN ('departing_user', 'replacement_editor')
GROUP BY AuthorID;
SSO and External Authentication
Textpattern does not include built-in LDAP, SAML, or OAuth support. Authentication is handled entirely through its internal user database.
For external authentication, options include:
HTTP Basic Auth overlay: Use your web server (Apache, Nginx) to add an additional authentication layer in front of the Textpattern admin:
# Apache .htaccess for additional auth on /textpattern/
<Location /textpattern>
AuthType Basic
AuthName "CMS Access"
AuthBasicProvider ldap
AuthLDAPURL "ldap://ldap.company.com:389/ou=People,dc=company,dc=com?uid"
Require valid-user
</Location>
Plugin-based SSO:
The smd_user_manager plugin supports custom authentication callbacks that can integrate with external systems.
Access Audit Checklist
- Review all users under Admin > Users quarterly
- Check for users with privilege level 0 (None) that should be permanently deleted
- Verify that only necessary users have Publisher (level 1) access
- Audit the
txp_userstable directly for any users not visible in the admin (corrupted records) - Check
last_accesscolumn for users who have not logged in recently - Review the
txp_logtable for unusual admin access patterns - Verify the admin URL is not publicly discoverable (consider renaming
/textpattern/directory) - Document all user additions and privilege changes