WordPress user meta is the metadata system WordPress uses to associate additional information with individual user accounts. It allows WordPress core, themes and plugins to store user-specific settings and data without adding a new column to the main users table every time someone invents another profile preference.
User meta can contain relatively simple information such as a preference or identifier, but it can also participate in important WordPress systems including capabilities, interface preferences, plugin configuration, profile extensions and user-specific application state.
Understanding user meta is particularly useful when developing plugins, debugging user accounts, auditing old WordPress installations or trying to work out why deleting a plugin did not delete the mysterious collection of keys it left behind.
This guide explains where WordPress user meta is stored, how it differs from the main user record, how to read and update it safely, why the same key can technically appear more than once, how arrays and objects are stored, how roles interact with user metadata, how user meta can be exposed through the REST API and what to check before deleting unfamiliar records.
What is WordPress user meta?
User meta is additional data associated with a WordPress user ID.
Conceptually, you might have:
User ID:
42
Core user data:
username
email
registration date
User meta:
preferred_language
dashboard_layout
company_name
profile_avatar_id
plugin_setting_x
The user account remains one object, but additional properties can be attached to it through metadata.
WordPress provides dedicated functions including get_user_meta(), add_user_meta(), update_user_meta() and delete_user_meta() for working with this data.
Where is user meta stored?
On a standard WordPress installation, user metadata is stored in:
wp_usermeta
The actual prefix may be different if the site uses a custom database table prefix.
A simplified usermeta table contains fields conceptually like:
umeta_id
user_id
meta_key
meta_value
For example:
umeta_id: 812
user_id: 42
meta_key: company_name
meta_value: Example Ltd
The WordPress wpdb class documentation exposes the core table references WordPress uses, including the user and usermeta tables.
User data and user meta are different
WordPress does not store every property of a user inside wp_usermeta.
The main user record is stored in the users table:
wp_users
That table contains core account properties such as:
- user ID;
- login name;
- password hash;
- display name;
- email address;
- website URL;
- registration date.
Additional information is generally stored separately as user metadata.
This distinction matters when debugging because searching wp_usermeta for a user’s registration date, for example, is usually the wrong place to look.
The registration date is not user meta
WordPress stores the account creation timestamp in the native:
user_registered
field of the user record.
That is why functionality displaying registration dates does not necessarily need to create another metadata key.
Before storing custom user information, check whether WordPress already provides a native field for it.
What kinds of data can user meta contain?
User meta can represent almost any serializable value associated with a user.
Typical examples include:
- profile preferences;
- interface settings;
- plugin-specific state;
- external system identifiers;
- company information;
- custom profile fields;
- notification preferences;
- avatar references;
- capability-related information;
- application workflow state.
The flexibility is useful precisely because WordPress does not need another database schema migration every time a plugin wants to remember that User 42 prefers compact tables.
How do you retrieve user meta?
The standard function is:
get_user_meta()
For example:
$company = get_user_meta(
$user_id,
'company_name',
true
);
The third argument controls whether WordPress returns one value or all values associated with that key.
The official get_user_meta() reference documents its return behavior.
Why does get_user_meta() have a $single parameter?
The WordPress metadata system allows more than one metadata row with the same key for the same user.
Suppose the database contains:
user_id: 42
meta_key: favorite_project
meta_value: alpha
user_id: 42
meta_key: favorite_project
meta_value: beta
This call:
get_user_meta(
42,
'favorite_project',
false
);
returns the collection of values.
Using:
get_user_meta(
42,
'favorite_project',
true
);
returns a single value.
Most settings should normally use one value per key
Although duplicate keys are supported, most normal profile settings conceptually represent one value.
For example:
company_name
timezone
dashboard_preference
avatar_id
usually have one current value rather than a list of independent rows.
That is why update_user_meta() is commonly used for settings.
How do you update user meta?
A typical update looks like:
update_user_meta(
$user_id,
'company_name',
'Example Ltd'
);
If the key does not already exist, update_user_meta() can create it.
If it exists, WordPress updates the corresponding metadata.
The exact behavior is documented in the official update_user_meta() reference.
Use add_user_meta() when you specifically need to add metadata
You can also use:
add_user_meta(
$user_id,
'favorite_project',
'alpha'
);
The function accepts a fourth argument controlling whether the key must be unique:
add_user_meta(
$user_id,
'company_name',
'Example Ltd',
true
);
With true, WordPress will not add another row if that user already has metadata with the same key.
See the official add_user_meta() documentation for the full behavior.
Do not use add_user_meta() every time a form is saved
If the field represents one setting, repeatedly calling:
add_user_meta()
without requiring uniqueness can produce:
company_name = Example Ltd
company_name = Example Ltd
company_name = Example Ltd
company_name = New Company Ltd
when what you really wanted was:
company_name = New Company Ltd
Use update_user_meta() for values that should have one current state.
How do you delete user meta?
Use:
delete_user_meta(
$user_id,
'company_name'
);
The function can also receive a specific metadata value when duplicate keys exist and only one matching record should be removed.
The official delete_user_meta() documentation explains both behaviors.
Deleting a key is different from storing an empty value
This:
update_user_meta(
$user_id,
'company_name',
''
);
does not mean the same thing as:
delete_user_meta(
$user_id,
'company_name'
);
The first can leave a metadata record containing an empty value.
The second removes the matching metadata.
This distinction can matter when application logic checks whether the metadata key exists at all.
Empty user meta values can be ambiguous
The get_user_meta() documentation notes that a nonexistent single value can return an empty string.
That means application code such as:
if ( ! get_user_meta(
$user_id,
'setting',
true
) ) {
// Assume no metadata exists.
}
can confuse:
Key does not exist
with:
Key exists but value is empty
If that difference matters, test existence deliberately instead of relying only on truthiness.
WordPress serializes arrays and objects automatically
User metadata values do not have to be plain strings.
You can store an array:
$preferences = [
'compact_mode' => true,
'items_per_page' => 50,
];
update_user_meta(
$user_id,
'dashboard_preferences',
$preferences
);
WordPress serializes the non-scalar value for database storage and restores the type when the value is retrieved through the metadata API.
The official add_user_meta() reference documents how arrays and objects are handled.
Do not manually serialize values before calling the metadata API
WordPress already knows how to serialize supported non-scalar values.
Doing this:
update_user_meta(
$user_id,
'preferences',
serialize( $preferences )
);
can lead to unnecessary double serialization or code that becomes harder to reason about.
Pass the PHP value and let the WordPress metadata API handle storage.
Simple values are generally stored as strings
The WordPress metadata API normalizes many scalar values when they reach database storage.
For example, values such as:
true
false
10
15.5
may be returned as string representations when they were stored as ordinary scalar metadata.
Do not rely on strict PHP type preservation for every scalar user meta value.
User meta keys should be named predictably
A plugin should generally use a distinctive prefix for custom metadata.
Instead of:
status
prefer something conceptually like:
myplugin_status
or:
towp_feature_state
This reduces collisions between unrelated plugins that happen to choose the same extremely imaginative word.
Should user meta keys start with an underscore?
WordPress conventions often use leading underscores for metadata intended to behave as internal or less prominently exposed implementation data.
For example:
_myplugin_internal_state
However, the underscore is a naming convention, not a security mechanism.
It does not make the value private from PHP code, database access or APIs that deliberately expose it.
User meta is not encrypted storage
This is an important security rule.
Do not assume that because information is stored in:
wp_usermeta
it is secret.
Administrators, database users, plugins and server-side code may be able to read it.
Do not store unnecessary plaintext secrets in user metadata.
Do not store passwords in user meta
WordPress already has a dedicated password authentication system.
Do not create:
myplugin_password
customer_password
external_password
metadata keys containing plaintext credentials simply because user meta is convenient.
If an integration genuinely needs secrets, design the credential storage and encryption strategy specifically for that threat model.
Sanitize user meta before saving it
User input should be validated and sanitized according to what the field is supposed to contain.
For plain text, WordPress provides helpers such as sanitize_text_field().
For example:
$company = sanitize_text_field(
$_POST['company_name'] ?? ''
);
update_user_meta(
$user_id,
'company_name',
$company
);
The correct sanitization function depends on the expected data type.
Escape user meta when outputting it
Sanitizing on input does not remove the need to escape on output.
For example:
echo esc_html(
get_user_meta(
$user_id,
'company_name',
true
)
);
The context of the output determines the appropriate escaping function.
WordPress’s escaping documentation explains the difference between HTML, attribute, URL and JavaScript contexts.
Check permissions before editing another user’s metadata
A form nonce does not prove that a user is authorized to change another account.
Before updating privileged user information, verify capabilities as appropriate.
For example:
if (
! current_user_can(
'edit_user',
$user_id
)
) {
return;
}
The official current_user_can() documentation covers capability checks.
For the wider permission model, see WordPress user roles and capabilities, explained.
Roles themselves interact with user metadata
WordPress roles and capabilities are not stored only as simple columns in wp_users.
The WP_User class manages role and capability information using user metadata associated with the account.
The exact capability meta key is site-prefix-dependent.
Conceptually, a normal single-site installation may contain metadata corresponding to:
wp_capabilities
wp_user_level
These values should not be edited casually with arbitrary SQL because WordPress uses them as part of authorization.
Role definitions and role assignments are different
There is another useful distinction.
The definition of what a role such as Administrator or Editor can do is not simply another independent usermeta row for every capability.
A user’s role assignment is associated with the user, while WordPress then resolves the capabilities granted by those roles.
The WP_User::get_role_caps() documentation explains how role capabilities and individual user capabilities are merged.
Individual capabilities can also be associated with a user
WordPress can grant a capability directly to an individual user rather than only through a role.
The WP_User::add_cap() method makes these changes persistent.
That flexibility is useful, but a site containing hundreds of one-off capability modifications can become very difficult to audit.
Prefer coherent role design where practical.
Do not manually edit capability user meta unless you understand the consequences
Changing capability metadata can immediately alter what an account is allowed to do.
A malformed value could:
- remove administrative access;
- grant excessive privileges;
- break role detection;
- create inconsistent user state.
TheOneWP Role Manager provides a structured interface for managing WordPress roles rather than requiring administrators to manipulate capability metadata directly.
Additional role systems may also use user meta
A plugin can build additional user-specific role state on top of WordPress’s native role system.
For example, TheOneWP Multi Role Assignment stores additional assigned role slugs in user metadata and merges the corresponding capabilities into WordPress’s capability checks.
This is a useful example of what user meta is good at: storing plugin-specific state associated with one user while leaving the main user table unchanged.
User profile fields are a common user meta use case
Suppose a membership site wants to store:
Company
Job title
Phone number
Preferred language
These fields can often be represented as user metadata.
For example:
company_name
job_title
phone_number
preferred_language
The account keeps its normal WordPress core fields while the application layers additional profile information on top.
Not every profile field belongs in user meta
Before creating:
custom_email
custom_display_name
custom_website
check whether WordPress already has:
user_email
display_name
user_url
Duplicating native information can create synchronization problems.
You eventually get two email addresses in two places and the thrilling administrative question of which one is supposed to be correct.
Avatars can involve user-specific metadata
A locally managed avatar system needs some way to associate the selected media asset with an individual user.
TheOneWP Local Avatar provides local profile image management instead of relying entirely on externally hosted Gravatar images.
The broader privacy implications of external avatars are covered in How Gravatar exposes WordPress user emails.
User interface preferences can also live in user meta
WordPress and plugins often need to remember preferences that differ from one administrator to another.
Examples include:
- dismissed notices;
- screen preferences;
- panel states;
- dashboard preferences;
- editor preferences.
User meta is a natural place for this because the preference belongs to one user rather than to the entire site.
Use options for site-wide state, user meta for user-specific state
A useful architectural distinction is:
Applies to entire site
→ option
Applies to one user
→ user meta
For example:
Site-wide API endpoint
→ option
User's preferred dashboard mode
→ user meta
Using a global option for per-user preferences often leads to increasingly elaborate arrays containing everybody’s state in one giant value.
User meta vs. post meta
The same basic metadata architecture also exists for other WordPress objects.
For example:
User-specific information
→ user meta
Post-specific information
→ post meta
Term-specific information
→ term meta
Comment-specific information
→ comment meta
The APIs are intentionally similar because they use WordPress’s broader metadata system.
You can register user meta
WordPress allows metadata keys to be formally registered.
For example:
register_meta(
'user',
'company_name',
[
'type' => 'string',
'single' => true,
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => false,
]
);
The official register_meta() documentation covers arguments including type, default value, sanitization, authorization and REST API exposure.
Registering meta makes the data contract clearer
An unregistered meta key is effectively just:
some key
with some value
A registered key can explicitly define:
- data type;
- whether it is single or multiple;
- default value;
- sanitization behavior;
- authorization behavior;
- REST visibility.
For structured plugin development, this makes the metadata considerably easier to reason about.
User meta is not automatically exposed through the REST API
Storing:
private_customer_reference
in user meta does not automatically mean every visitor can retrieve it from a REST endpoint.
REST exposure depends on registration, endpoint behavior and permissions.
If metadata is registered with:
'show_in_rest' => true
you are explicitly making it available through the relevant REST metadata schema, subject to WordPress’s endpoint and authorization rules.
Do not enable REST visibility merely because the argument exists.
Think carefully before exposing user meta through REST
User metadata may contain:
- internal identifiers;
- profile information;
- administrative preferences;
- integration state;
- security-related information.
Expose only data the API genuinely needs.
For the wider security model, see WordPress REST API security basics.
REST API authorization still matters
show_in_rest should not be treated as the only security decision.
The metadata registration API supports an:
auth_callback
that can participate in deciding whether the current request may modify protected metadata.
Read access is also affected by the permissions and schema of the REST endpoint involved.
Design REST exposure as an API contract, not as a convenient way to dump the usermeta table into JSON and see what happens.
User meta can be queried
WordPress can query users based on metadata.
For example, an application might need:
All users
where company_type = agency
WordPress provides the WP_User_Query class for retrieving users with different query parameters.
Metadata conditions can be included through meta queries.
Do not build enormous applications around unindexed meta queries casually
User meta is flexible, but flexibility does not mean every relational data model belongs there.
Imagine:
5,000,000 usermeta rows
Query:
find users where
several arbitrary meta values match
That can become expensive compared with a database schema designed specifically for the application’s workload.
User meta is excellent for additional properties.
It is not automatically the ideal replacement for every custom table humanity might otherwise have to design.
When should you consider a custom table instead?
A custom table may be worth considering when the data:
- has millions of records;
- requires complex relational queries;
- needs specialized indexes;
- is queried heavily by several columns;
- represents independent records rather than attributes of the user;
- has its own lifecycle separate from the account.
For example, storing every historical financial transaction as another user meta row would usually be a questionable architecture.
User meta can accumulate database bloat
Plugins can continuously add metadata to users.
Over time, wp_usermeta may contain keys belonging to:
- current plugins;
- deleted plugins;
- old themes;
- previous membership systems;
- abandoned integrations;
- temporary migrations.
This does not mean unfamiliar metadata should immediately be deleted.
It means the table may deserve periodic auditing.
Removing a plugin does not guarantee its user meta disappears
Plugins choose their own uninstall behavior.
Some remove their metadata.
Some intentionally preserve it for later reinstallation.
Some simply leave it behind.
Before removing unknown keys after a plugin cleanup, see A WordPress plugin cleanup checklist.
Do not delete user meta based only on the key name
Suppose you find:
oldplugin_member_id
oldplugin_preferences
oldplugin_access_state
The names suggest a plugin.
Before deleting them, determine:
- whether the plugin is truly gone;
- whether another plugin migrated or still reads the data;
- whether the key affects roles or access;
- whether the information has business value;
- whether a backup exists.
Use Database Manager when investigating unfamiliar metadata
TheOneWP Database Manager can help inspect the database structure and records when deeper troubleshooting is required.
For user metadata, useful questions include:
Which keys occur most often?
Which plugin owns them?
How many users have them?
When was the associated feature removed?
Inspection should precede deletion, a principle databases keep trying to teach people through increasingly expensive demonstrations.
Do not edit wp_usermeta directly when a WordPress API exists
You can technically run SQL such as:
UPDATE wp_usermeta
SET meta_value = 'x'
WHERE user_id = 42
AND meta_key = 'example';
but normal application code should generally prefer:
update_user_meta()
WordPress APIs provide predictable handling and participate in metadata hooks and caches that raw SQL can bypass.
User metadata is cached
WordPress’s metadata APIs participate in the WordPress object cache.
This is another reason direct database writes can create confusing situations within a request or persistent-cache environment.
If application code bypasses WordPress to change metadata directly, cached values may not reflect the database change immediately unless the relevant cache is invalidated correctly.
Bulk operations still need care
There are legitimate situations where direct SQL is useful, especially for large migrations.
But a bulk operation should account for:
- cache invalidation;
- serialized values;
- duplicate meta keys;
- multisite prefixes;
- plugin hooks;
- authorization-related metadata.
Fast and correct are not mutually exclusive, despite a surprising amount of production maintenance apparently being designed around proving otherwise.
User meta and WordPress multisite
Multisite makes user metadata more interesting because WordPress users can participate across multiple sites within the same network.
Some user metadata is global to the account, while capability-related metadata can be site-specific through prefixed keys.
For example, capability metadata may include the relevant site’s database prefix.
Do not assume that a capability key copied from one site can simply be reused for another site in the network.
Roles can differ between sites in a multisite network
A network user might be:
Administrator
on Site A
Subscriber
on Site B
The account is the same WordPress user, but site-specific authorization differs.
This is one reason capability-related usermeta keys must be treated more carefully than ordinary profile fields.
User sessions also interact with user metadata
WordPress session-token handling can persist session information associated with a user.
The core WP_User_Meta_Session_Tokens class is specifically responsible for user session tokens backed by user metadata.
This is a good reminder that wp_usermeta can contain security-sensitive operational state as well as harmless profile preferences.
Do not clean security-related user meta casually
Unfamiliar metadata can belong to:
- sessions;
- two-factor authentication;
- application passwords;
- login security plugins;
- access-control systems;
- role assignments.
A cleanup query that treats every strange key as garbage can log users out, disable account protections or change authorization behavior.
Last-login information is an example of user-specific state
WordPress core provides the current account and authentication system, but many administrative workflows benefit from knowing when an account was most recently used.
TheOneWP Last Login adds last-login information to user management so administrators can identify active and potentially dormant accounts more easily.
That type of data belongs conceptually to an individual user rather than to the site globally.
Do not confuse last login with registration date
These answer different questions:
Registration date
→ When was the account created?
Last login
→ When was the account last used?
The first is represented by WordPress’s native account registration field.
The second normally requires tracking activity because WordPress does not use user_registered as a login timestamp.
User meta can support per-user admin state
Suppose an admin-interface feature needs to remember:
User 1 dismissed notice A
User 2 has not dismissed notice A
A site-wide option cannot represent that distinction cleanly without building its own nested user map.
User metadata naturally associates the state with each account.
Deleting users should be considered separately from deleting their metadata
User meta exists because a user exists.
When removing accounts, use WordPress’s user-management APIs and workflows rather than deleting only the row in wp_users.
Otherwise you risk leaving orphaned metadata behind.
Orphaned user meta can exist
An orphaned record conceptually looks like:
wp_usermeta:
user_id = 155
wp_users:
ID 155 does not exist
This can occur after:
- incorrect manual SQL deletion;
- failed migrations;
- buggy plugins;
- partial imports.
Such records may be candidates for cleanup, but investigate the environment before deleting large sets automatically.
User meta should follow the lifecycle of the feature that owns it
When building a plugin, define what should happen when:
- the feature is disabled;
- the plugin is deactivated;
- the plugin is uninstalled;
- the user account is deleted.
Not every one of these events should necessarily delete the metadata.
For example, deactivating a plugin temporarily should often preserve configuration.
Permanent uninstall may reasonably offer a full cleanup path.
Document your custom user meta keys
For a plugin or large application, keep track of metadata keys intentionally.
For example:
myplugin_company_id
myplugin_dashboard_mode
myplugin_last_sync
myplugin_notification_preferences
For each key, document:
- purpose;
- data type;
- whether multiple values are allowed;
- who may read it;
- who may update it;
- whether it is exposed through REST;
- when it should be deleted.
A practical user meta example
Suppose you want to store a user’s department.
You could register the key:
register_meta(
'user',
'company_department',
[
'type' => 'string',
'single' => true,
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => false,
]
);
Then save it:
update_user_meta(
$user_id,
'company_department',
'Development'
);
Retrieve it:
$department = get_user_meta(
$user_id,
'company_department',
true
);
And display it safely:
echo esc_html( $department );
Example: storing several preferences in one array
You could store:
[
'compact_mode' => true,
'per_page' => 50,
'notifications' => false,
]
under one key:
dashboard_preferences
This can be convenient when the settings are always read and written together.
One large array or several meta keys?
There is no universal answer.
Separate keys are useful when:
- values are queried independently;
- values change independently;
- different permissions apply;
- you want simpler individual updates.
One structured value can make sense when:
- the values form one coherent configuration object;
- they are always retrieved together;
- they do not need independent metadata queries.
Do not create giant serialized user records
User meta is flexible enough that you could store an enormous application state array in one field.
That does not mean you should.
Very large serialized objects are harder to:
- query;
- partially update;
- debug;
- migrate;
- inspect manually.
Choose a structure appropriate to how the data will actually be used.
Common WordPress user meta mistakes
Assuming everything about a user lives in wp_usermeta
Core account fields such as login, email and registration date live in the main users table.
Using add_user_meta() repeatedly for a single setting
You can create duplicate rows when the field should have one current value.
Confusing an empty value with a nonexistent key
get_user_meta() can return values that require careful existence checks.
Manually serializing arrays
The WordPress metadata API already handles serialization.
Using user meta for plaintext passwords
Convenient database storage is not credential security.
Failing to sanitize input
User-controlled metadata should be validated and sanitized according to its expected format.
Failing to escape output
Stored data can still become unsafe when rendered in the wrong context.
Updating another user’s metadata without capability checks
Knowing a user ID does not grant permission to modify that account.
Exposing every custom field through REST
REST visibility should be intentional.
Editing capability metadata directly
Role and capability state affects authorization and should use WordPress APIs or controlled administration tools.
Deleting unknown plugin user meta blindly
The key may still support active functionality or security state.
Using user meta as a replacement for every possible custom table
High-volume relational applications may need a more appropriate schema.
WordPress user meta checklist
- Check whether WordPress already has a native user field for the data.
- Use user meta for information that belongs to one account.
- Use options for site-wide configuration.
- Use predictable prefixed meta keys.
- Choose whether the key should contain one or multiple values.
- Use
update_user_meta()for ordinary single-value settings. - Use
add_user_meta()deliberately when multiple records are appropriate. - Use
delete_user_meta()when the metadata should actually disappear. - Do not confuse empty values with nonexistent keys.
- Let WordPress serialize arrays and objects.
- Sanitize user-controlled input.
- Escape values when outputting them.
- Check capabilities before modifying other accounts.
- Register important metadata where a clear schema is useful.
- Expose metadata through REST only when required.
- Protect sensitive operational metadata.
- Do not edit roles and capabilities with random database updates.
- Audit abandoned plugin metadata carefully.
- Consider query performance on very large usermeta tables.
- Use custom tables when the data model genuinely requires them.
- Back up before large cleanup or migration operations.
Related WordPress user and backend guides
For the wider user, permissions, database and API cluster, continue with:
- WordPress user roles and capabilities, explained
- WordPress REST API security basics
- A WordPress plugin cleanup checklist
- WordPress database bloat, explained
- How Gravatar exposes WordPress user emails
- WordPress privacy and third-party requests
- Last Login
- Local Avatar
- Multi Role Assignment
- Role Manager
- Database Manager
Final thoughts
WordPress user meta is the flexible layer that allows additional information to follow an individual user without constantly expanding the core users table.
It can store profile fields, preferences, plugin state and application-specific information, while WordPress itself also uses user metadata as part of important systems such as roles, capabilities and session management.
That flexibility comes with responsibility. User meta should not become a dumping ground for secrets, enormous application datasets or undocumented plugin state. Keys should be named clearly, values should be sanitized, access should be authorized and REST exposure should be deliberate.
TheOneWP Role Manager and Multi Role Assignment show how user-specific authorization state can interact with WordPress’s user system, while Last Login and Local Avatar illustrate the broader category of functionality that depends on information associated with individual accounts.
The underlying rule is simple: if the information belongs to one WordPress user and does not already have a native user field, user meta is often the right place to start.
Just remember that “WordPress lets me put this in wp_usermeta” and “this is a good data model” remain two entirely separate statements.

