wp-includes/post.php:2735Save a custom field on a post with update_post_meta(), updating the existing row or adding the key when the post does not have it yet. It returns the new meta ID when the key was added, true on a change, and false when the value is unchanged or the update fails. $prev_value targets one row when a key holds several values; revision IDs are redirected to the parent post.
Updates a post meta field based on the given post ID.
$post_idint$meta_keystring$meta_valuemixed$prev_valuemixedoptional''int|boolEvery 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.
The return value differs between the first write and later ones, which trips up code that checks it.
delete_post_meta( 4, 'event_date' );
$first = update_post_meta( 4, 'event_date', '2026-09-01' );
$second = update_post_meta( 4, 'event_date', '2026-09-08' );
$same = update_post_meta( 4, 'event_date', '2026-09-08' );
echo 'first write: ', var_export( $first, true ), " (the new meta_id)\n";
echo 'changed value: ', var_export( $second, true ), "\n";
echo 'unchanged value:', var_export( $same, true ), " (false, not an error)\n";
echo 'stored: ', get_post_meta( 4, 'event_date', true );Writing the value it already holds returns false, so never treat false as failure.
When a key holds several rows, $prev_value picks the one to overwrite instead of replacing them all.
delete_post_meta( 5, 'badge' );
add_post_meta( 5, 'badge', 'silver' );
add_post_meta( 5, 'badge', 'bronze' );
// Targets one row; without $prev_value both rows would collapse into one.
update_post_meta( 5, 'badge', 'gold', 'silver' );
print_r( get_post_meta( 5, 'badge' ) );Omitting $prev_value on a multi-row key deletes the extras, which is rarely what you want.
function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) { // Make sure meta is updated for the post, not for a revision. $the_post = wp_is_post_revision( $post_id ); if ( $the_post ) { $post_id = $the_post; } return update_metadata( 'post', $post_id, $meta_key, $meta_value, $prev_value );}Introduced in 1.5.0. Unchanged from 6.7.7 through 7.1.0.
Signature, return type and hooks compared across 5 parsed releases.
src/wp-includes/post.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.