wppaste
WordPress

update_user_meta( int $user_id, string $meta_key, mixed $meta_value, mixed $prev_value = '' ): int|bool

Since
3.0.0
Source
wp-includes/user.php:1309

Writes a value to a user's meta key, creating the row if none exists yet. Pass $prev_value to target one entry among several rows that share the same key for a user, since otherwise every matching row is updated. The return value is an int (new meta ID), true, or false depending on whether the row was added, changed, or already matched what's stored, so check the type rather than assuming a plain boolean. Pair it with get_user_meta() to read the value back after writing it.

Updates user meta field based on user ID.

Description

Use the $prev_value parameter to differentiate between meta fields with the same key and user ID.

If the meta field for the user does not exist, it will be added.

For historical reasons both the meta key and the meta value are expected to be "slashed" (slashes escaped) on input.

Compatibility

WordPress
since 3.0.0
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$user_idint
User ID.
$meta_keystring
Metadata key.
$meta_valuemixed
Metadata value. Must be serializable if non-scalar.
$prev_valuemixedoptional
Previous value to check before updating.
If specified, only update existing metadata entries with this value. Otherwise, update all entries. Default empty.Default: ''

Return value

int|bool
Meta ID if the key didn't exist, true on successful update, false on failure or if the value passed to the function is the same as the one that is already in the database.

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Save a per-user preference flag

The sandbox has an administrator already logged in, so its user ID can be used directly without creating a new user.

$user_id = get_current_user_id();

$result = update_user_meta( $user_id, 'newsletter_opt_in', '1' );

$value = get_user_meta( $user_id, 'newsletter_opt_in', true );

printf( 'update_user_meta() returned: %s, stored value: %s', esc_html( var_export( $result, true ) ), esc_html( $value ) );

The first call on a fresh install returns the new meta ID rather than true, since the row does not exist yet.

Update one entry when a user has several meta rows sharing the same key

A second user is created with two 'shift_note' meta rows under the same key, then $prev_value is used to update only the matching one.

$user_id = (int) get_option( 'meta_demo_user_id' );

$updated = update_user_meta( $user_id, 'shift_note', 'evening shift, updated', 'evening shift' );

$notes = get_user_meta( $user_id, 'shift_note' );

printf( 'Update result: %s', esc_html( var_export( $updated, true ) ) );
echo '<pre>' . esc_html( print_r( $notes, true ) ) . '</pre>';

Without the $prev_value argument, update_user_meta() would overwrite every 'shift_note' row for this user with the same new value.

Common problems and fixes · 4

Why does update_user_meta() return false even though I passed a real value?

The function returns false whenever the value passed in matches what's already stored for that key, since update_metadata() treats that as nothing to change. It also returns false if $prev_value is given but no row currently matches it.

Why did update_user_meta() overwrite all my meta rows for that key instead of one?

When a user has multiple rows under the same meta key and $prev_value is left empty, every row matching that key is updated because the function has nothing to narrow the match against.

Why is the return value sometimes a number instead of true?

If the meta key doesn't exist yet for that user, update_user_meta() adds a new row instead of updating one, and the return value is the new meta ID (an int), not true. Only an existing row that actually changes returns true.

Do I need to escape my meta value before passing it in?

The docblock notes that both the meta key and meta value are expected to be slashed on input for historical reasons, since WordPress later removes those slashes internally.

Alternatives and related functions

update_metadata
When the meta type isn't a user, since this is the shared function behind update_user_meta(), update_post_meta(), and update_term_meta().
get_user_meta
When you need to read a value back rather than write one.
add_user_meta
When you want to add another row under the same key instead of updating an existing one.
delete_user_meta
When you need to remove a meta entry rather than change its value.

Performance profile

How much work a call to update_user_meta() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Light

Only touches the object cache, via wp_cache_delete().

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
12

Executed per call on PHP 8.5. The body compiles to 12.

Plugin surface
None

Nothing here hands control to plugin code.

Called by
39

39 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • hookthird-party callbacksapply_filters()one call below update_user_meta()
  • serializeserialisationmaybe_serialize()one call below update_user_meta()
  • cacheobject cachewp_cache_delete()one call below update_user_meta()

Further down the call graph this can also reach query, option and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 1 distinct outcome

One number would be a lie: the work depends on which branch runs. These are every distinct cost update_user_meta() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
always12update_metadata()

Across PHP versions

Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 12 instructions, 12 executed per call, 0 branches. The work does not change between versions.

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Uses · 1

  • update_metadata()Updates metadata for the specified object. If no value already exists for the specified object ID and metadata key, the metadata will be added.

Used by · 39

Show all 39

Source code

function update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' ) {	return update_metadata( 'user', $user_id, $meta_key, $meta_value, $prev_value );}

Changelog

Introduced in 3.0.0. Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

About this page

Parsed data
Generated from the wordpress-develop 7.0.4 tag, from src/wp-includes/user.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.