WordPress User Profile Fields Example: Save User Meta Safely
Add custom WordPress user profile fields with capability checks, validation, and clean user meta storage.
Published
April 25, 2026
Reading Time
1 min read
Updated
April 25, 2026

Implementation Notes
Extension points, code paths, and implementation choices that should survive contact with production.
Best For
WordPress developers, agencies, and technical teams building custom plugin or theme functionality with cleaner operational defaults.
Primary Topics
Editorial Focus
Build Pattern: Extension points, code paths, and implementation choices that should survive contact with production. Updated on April 25, 2026.
Full Report
Last reviewed: April 25, 2026
WordPress user profiles are a practical place to store small pieces of operational metadata such as department names, support escalation IDs, Slack handles, or editorial approval flags. The failure mode is treating profile fields like trusted input and saving them without capability checks or clear validation rules.
This guide shows how to add a custom field to user profiles, save it safely for both self-edits and administrator edits, and keep the stored user meta predictable.
Render the field on both profile screens
<?php
add_action( 'show_user_profile', 'vulnwp_render_support_handle_field' );
add_action( 'edit_user_profile', 'vulnwp_render_support_handle_field' );
function vulnwp_render_support_handle_field( WP_User $user ) {
$value = get_user_meta( $user->ID, 'vulnwp_support_handle', true );
?>
<h2>Support Metadata</h2>
<table class=\"form-table\" role=\"presentation\">
<tr>
<th><label for=\"vulnwp-support-handle\">Support handle</label></th>
<td>
<input type=\"text\" name=\"vulnwp_support_handle_input\" id=\"vulnwp-support-handle\" value=\"<?php echo esc_attr( $value ); ?>\" class=\"regular-text\" />
<p class=\"description\">Internal handle used by the support team.</p>
</td>
</tr>
</table>
<?php
}
Both profile hooks are required because users editing themselves and administrators editing other users do not hit the same action.
Save the field on both update paths
add_action( 'personal_options_update', 'vulnwp_save_support_handle_field' );
add_action( 'edit_user_profile_update', 'vulnwp_save_support_handle_field' );
function vulnwp_save_support_handle_field( $user_id ) {
if ( ! current_user_can( 'edit_user', $user_id ) ) {
return false;
}
$value = isset( $_POST['vulnwp_support_handle_input'] )
? sanitize_text_field( wp_unslash( $_POST['vulnwp_support_handle_input'] ) )
: '';
if ( '' === $value ) {
delete_user_meta( $user_id, 'vulnwp_support_handle' );
return true;
}
return update_user_meta( $user_id, 'vulnwp_support_handle', $value );
}
The input name and stored meta key are intentionally different. That avoids a long-standing edge case documented in WordPress notes where identical keys can lead to empty posted values.
Validate before the save completes
If a field needs stricter rules, use user_profile_update_errors to block invalid values before WordPress finalizes the profile update.
add_action( 'user_profile_update_errors', 'vulnwp_validate_support_handle_field', 10, 3 );
function vulnwp_validate_support_handle_field( WP_Error $errors, $update, $user ) {
$value = isset( $_POST['vulnwp_support_handle_input'] )
? sanitize_text_field( wp_unslash( $_POST['vulnwp_support_handle_input'] ) )
: '';
if ( '' !== $value && ! preg_match( '/^[a-z0-9._-]{3,32}$/i', $value ) ) {
$errors->add( 'vulnwp_support_handle', __( 'Support handle format is invalid.', 'vulnwp' ) );
}
}
Production checklist
- Render the field on both self-edit and admin-edit profile screens.
- Check
edit_usercapability before saving. - Sanitize the posted value explicitly.
- Delete empty metadata instead of storing empty strings.
- Use
user_profile_update_errorsfor strict validation. - Keep internal-only metadata out of public templates unless there is a real need.
Common mistakes
- Hooking only one profile screen. The field then disappears on half the edit flows.
- No capability check. Profile metadata still needs authorization.
- Using the same field name and meta key. That can produce confusing empty values.
- Storing free-form internal identifiers without validation. Bad data spreads quickly.
- Exposing private user metadata on the front end. Internal support fields should stay internal.
Related reading
If profile data later influences role checks, pair it with the roles and capabilities article. If it is exposed through APIs, combine it with the metadata registration guide and keep the field private unless there is a clear reason to publish it.


