2026年11月14日

2026年11月14日

WordPress User Meta: get_user_meta, Profile Fields and WP-CLI

This article is a localized edition of the Japanese original. Read the Japanese original

User meta is how WordPress stores extra information for each user, such as a phone number, a company name or a point balance. Each value is saved in the wp_usermeta table (when your table prefix is wp_) as a row of user ID, key and value. You read and write it from a plugin or your theme's functions.php with a set of dedicated functions.

The behavior of the functions and hooks in this article was checked against the WordPress core source code (6.9).

The four basic functions

<?php
$user_id = get_current_user_id(); // ID of the logged-in user (0 if not logged in)

// Add: with the 4th argument set to true, nothing is added if the key already exists
add_user_meta( $user_id, 'myplugin_points', 0, true );

// Get: with the 3rd argument set to true, a single value is returned
$points = (int) get_user_meta( $user_id, 'myplugin_points', true );

// Update: the key is added if it does not exist
update_user_meta( $user_id, 'myplugin_points', $points + 10 );

// Delete
delete_user_meta( $user_id, 'myplugin_points' );
Function Return value
add_user_meta() The ID of the new row, or false if nothing was added
get_user_meta( $id, $key, true ) The value, or an empty string '' if the key does not exist
get_user_meta( $id, $key, false ) An array of all values for that key, or an empty array if there are none
get_user_meta( $id ) Without a key, all meta for that user (an array per key)
update_user_meta() The new row ID when the key was added, true when it was updated, and false when the value was unchanged or the update failed
delete_user_meta() true if deleted, false if not

Watch the type of the value you get back. Numbers and booleans are stored as strings, so saving 100 returns "100", and saving false returns "". Cast with (int) or similar when you need a number. If you save an array, WordPress serializes it on save and turns it back into an array when you read it.

Give your keys a prefix such as your plugin name so they do not collide with other plugins (this article uses myplugin_).

Add fields to the profile screen

This example adds phone number and company name fields to the Profile and Edit User screens in the admin.

Hook When it runs
show_user_profile When your own profile is displayed
edit_user_profile When the edit screen of another user is displayed
personal_options_update When your own profile is saved
edit_user_profile_update When another user is saved from the edit screen
<?php
// Display the fields ($user is a WP_User)
add_action( 'show_user_profile', 'myplugin_profile_fields' );
add_action( 'edit_user_profile', 'myplugin_profile_fields' );

function myplugin_profile_fields( $user ) {
	$phone   = get_user_meta( $user->ID, 'myplugin_phone', true );
	$company = get_user_meta( $user->ID, 'myplugin_company', true );
	?>
	<h2>Additional information</h2>
	<table class="form-table" role="presentation">
		<tr>
			<th><label for="myplugin_phone">Phone number</label></th>
			<td><input type="tel" id="myplugin_phone" name="myplugin_phone" value="<?php echo esc_attr( $phone ); ?>" class="regular-text"></td>
		</tr>
		<tr>
			<th><label for="myplugin_company">Company</label></th>
			<td><input type="text" id="myplugin_company" name="myplugin_company" value="<?php echo esc_attr( $company ); ?>" class="regular-text"></td>
		</tr>
	</table>
	<?php
}

// Save the fields
add_action( 'personal_options_update', 'myplugin_save_profile_fields' );
add_action( 'edit_user_profile_update', 'myplugin_save_profile_fields' );

function myplugin_save_profile_fields( $user_id ) {
	if ( ! current_user_can( 'edit_user', $user_id ) ) {
		return;
	}
	if ( isset( $_POST['myplugin_phone'] ) ) {
		update_user_meta( $user_id, 'myplugin_phone', sanitize_text_field( wp_unslash( $_POST['myplugin_phone'] ) ) );
	}
	if ( isset( $_POST['myplugin_company'] ) ) {
		update_user_meta( $user_id, 'myplugin_company', sanitize_text_field( wp_unslash( $_POST['myplugin_company'] ) ) );
	}
}
  • Before the save hooks run, core's wp-admin/user-edit.php already verifies the form nonce with check_admin_referer( 'update-user_' . $user_id ), so you do not need your own nonce for these fields. Check permissions with current_user_can( 'edit_user', $user_id ).
  • WordPress adds backslashes to $_POST values, so remove them with wp_unslash() and then clean the value with sanitize_text_field().

To confirm it works, save the profile, reload the screen and check that your values are still there.

Filter users by meta value

Pass meta_key and related arguments to get_users() to filter users by a meta value. Set meta_type to NUMERIC to compare as numbers. Without it, values are compared as strings, and "9" counts as greater than "100".

<?php
// 20 users with 100 points or more, highest first
$users = get_users( array(
	'meta_key'     => 'myplugin_points',
	'meta_value'   => 100,
	'meta_compare' => '>=',
	'meta_type'    => 'NUMERIC',
	'orderby'      => 'meta_value_num',
	'order'        => 'DESC',
	'number'       => 20,
) );

foreach ( $users as $user ) {
	$points = (int) get_user_meta( $user->ID, 'myplugin_points', true );
	echo esc_html( $user->display_name . ': ' . $points . ' points' ) . '<br>';
}

// Users who have no phone number meta
$no_phone = get_users( array(
	'meta_query' => array(
		array(
			'key'     => 'myplugin_phone',
			'compare' => 'NOT EXISTS',
		),
	),
) );

Filtering by meta value gets slow when you have many users. For lists you use often, consider caching the result for a while (for example in a transient).

View and change user meta with WP-CLI

The WP-CLI wp user meta command lets you view and change user meta. For <user>, give a user ID, login name or email address.

# Show all meta for user ID 1
wp user meta list 1

# Show the value of one key
wp user meta get 1 myplugin_points

# Change a value (added if the key does not exist)
wp user meta update 1 myplugin_points 500

# Delete
wp user meta delete 1 myplugin_points

wp user list accepts the same arguments as get_users() in the form --argument=value.

# List users with more than 0 points
wp user list --meta_key=myplugin_points --meta_value=0 --meta_compare='>' --meta_type=NUMERIC --fields=ID,user_login,display_name

# Show only the number of matching users
wp user list --meta_key=myplugin_points --meta_value=0 --meta_compare='>' --meta_type=NUMERIC --format=count

Creating users, changing roles and more are covered in How to use the WP-CLI user command.

Set an initial value for all users at once

Here is an example for when a new plugin feature needs an initial value for every existing user. Long code passed to wp eval easily breaks on shell quoting and escaping, so put it in a PHP file and run it with wp eval-file.

<?php
// init-points.php (run: wp eval-file init-points.php)
$user_ids = get_users( array( 'fields' => 'ID' ) );
$count    = 0;

foreach ( $user_ids as $user_id ) {
	// Set 0 only for users who do not have the key yet
	if ( ! metadata_exists( 'user', (int) $user_id, 'myplugin_points' ) ) {
		add_user_meta( (int) $user_id, 'myplugin_points', 0, true );
		$count++;
	}
}

WP_CLI::success( $count . ' users initialized' );
  • metadata_exists() only checks whether the key exists. If you test the result of get_user_meta() instead, users whose value is 0 are also treated as having no value.
  • On multisite, get_users() returns only users of the current site by default.
  • Back up the database before running it on production.

Use user meta in the REST API

By default, user meta is not included in the REST API (/wp-json/wp/v2/users/<id>). To read or write it from the block editor or an external app, register it with register_meta() and set show_in_rest to true.

<?php
add_action( 'init', function () {
	register_meta( 'user', 'myplugin_points', array(
		'type'              => 'integer',
		'single'            => true,
		'default'           => 0,
		'show_in_rest'      => true,
		'sanitize_callback' => 'absint',
	) );
} );

Once a default is registered, get_user_meta( $id, 'myplugin_points', true ) returns that value (here 0) instead of an empty string for users who do not have the key.

After registration, the value appears under meta in the user's REST response, and anyone allowed to edit that user can update it. Keys that start with _ are treated as protected meta and cannot be updated over REST unless an auth_callback allows it.

Things to watch out for

  • Do not store secrets such as passwords or API keys in user meta as plain text.
  • To remove the meta when your plugin is deleted, delete it for all users in uninstall.php, for example with delete_metadata( 'user', 0, 'myplugin_points', '', true ) (the 5th argument true targets every user).
  • Meta attached to posts (custom fields) uses different functions (such as get_post_meta()) and a different table (wp_postmeta).

Summary

  • Read and write user meta with add_user_meta(), get_user_meta(), update_user_meta() and delete_user_meta(); values come back as strings, so convert the type when needed
  • Show profile fields with show_user_profile and edit_user_profile, and save them with personal_options_update and edit_user_profile_update after checking permissions
  • Set meta_type to NUMERIC when filtering by numbers
  • In WP-CLI, use wp user meta to view and change values, and run bulk jobs with wp eval-file

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲