Index: user.php
===================================================================
--- user.php	(revision 11025)
+++ user.php	(working copy)
@@ -286,7 +286,196 @@
 // User meta functions
 //
 
+//
+// User meta functions
+//
+
+
+
 /**
+ * Add meta data field to a user.
+ *
+ *
+ * @since XXX
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/add_user_meta
+ *
+ * @param int $user_id User ID.
+ * @param string $key Metadata name.
+ * @param mixed $value Metadata value.
+ * @param bool $unique Optional, default is false. Whether the same key should not be added.
+ * @return bool False for failure. True for success.
+ */
+function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
+	global $wpdb;
+
+	// expected_slashed ($meta_key)
+	$meta_key = stripslashes($meta_key);
+
+	if ( $unique && $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->usermeta WHERE meta_key = %s AND user_id = %d", $meta_key, $user_id ) ) )
+		return false;
+
+	$meta_value = maybe_serialize( stripslashes_deep($meta_value) );
+
+	$wpdb->insert( $wpdb->usermeta, compact( 'user_id', 'meta_key', 'meta_value' ) );
+
+	wp_cache_delete($user_id, 'user_meta');
+
+	return true;
+}
+
+/**
+ * Remove matching metadata from a user.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since xxx
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/delete_user_meta
+ *
+ * @param int $user_id User ID
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata value.
+ * @return bool False for failure. True for success.
+ */
+function delete_user_meta($user_id, $meta_key, $meta_value = '') {
+	global $wpdb;
+
+	// expected_slashed ($meta_key, $meta_value)
+	$meta_key = stripslashes( $meta_key );
+	$meta_value = maybe_serialize( stripslashes_deep($meta_value) );
+
+	if ( empty( $meta_value ) )
+		$meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key ) );
+	else
+		$meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s AND meta_value = %s", $user_id, $meta_key, $meta_value ) );
+
+	if ( !$meta_id )
+		return false;
+
+	if ( empty( $meta_value ) )
+		$wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key ) );
+	else
+		$wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s AND meta_value = %s", $user_id, $meta_key, $meta_value ) );
+
+	wp_cache_delete($user_id, 'user_meta');
+
+	return true;
+}
+
+/**
+ * Retrieve user meta field for a user.
+ *
+ * @since xxx
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/get_user_meta
+ *
+ * @param int $user_id User ID.
+ * @param string $key The meta key to retrieve.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
+ */
+function get_user_meta($user_id, $key, $single = false) {
+	$user_id = (int) $user_id;
+
+	$meta_cache = wp_cache_get($user_id, 'user_meta');
+
+	if ( !$meta_cache ) {
+		update_usermeta_cache($user_id);
+		$meta_cache = wp_cache_get($user_id, 'user_meta');
+	}
+
+	if ( isset($meta_cache[$key]) ) {
+		if ( $single ) {
+			return maybe_unserialize( $meta_cache[$key][0] );
+		} else {
+			return array_map('maybe_unserialize', $meta_cache[$key]);
+		}
+	}
+
+	return '';
+}
+
+/**
+ * Update user meta field based on User ID.
+ *
+ * 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.
+ *
+ * @since xxx
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/update_user_meta
+ *
+ * @param int $user_id User ID.
+ * @param string $key Metadata key.
+ * @param mixed $value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return bool False on failure, true if success.
+ */
+function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
+	global $wpdb;
+
+	// expected_slashed ($meta_key)
+	$meta_key = stripslashes($meta_key);
+
+	if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->usermeta WHERE meta_key = %s AND user_id = %d", $meta_key, $user_id ) ) ) {
+		return add_user_meta($user_id, $meta_key, $meta_value);
+	}
+
+	$meta_value = maybe_serialize( stripslashes_deep($meta_value) );
+
+	$data  = compact( 'meta_value' );
+	$where = compact( 'meta_key', 'user_id' );
+
+	if ( !empty( $prev_value ) ) {
+		$prev_value = maybe_serialize($prev_value);
+		$where['meta_value'] = $prev_value;
+	}
+
+	$wpdb->update( $wpdb->usermeta, $data, $where );
+	wp_cache_delete($user_id, 'user_meta');
+	return true;
+}
+
+/**
+ * Delete everything from user meta matching meta key.
+ *
+ * @since xxx
+ * @uses $wpdb
+ *
+ * @param string $user_meta_key Key to search for when deleting.
+ * @param string $operator The SQL operator. Can be any of LIKE, NOT LIKE, REGEXP, NOT REGEXP
+* @return bool Whether the user meta key was deleted from the database
+ */
+function delete_user_meta_by_key($user_meta_key, $operator = false) {
+	global $wpdb;
+	switch ( $operator ) {
+		case 'LIKE':
+		case 'NOT LIKE':
+		case 'REGEXP':
+		case 'NOT REGEXP':
+			break;
+		default:
+			$operator = 'LIKE';
+	}
+
+	$user_ids = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT user_id FROM $wpdb->usermeta WHERE meta_key LIKE %s", $user_meta_key));
+
+	if ( $user_ids ) {
+		$wpdb->query($wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE meta_key LIKE %s", $user_meta_key));
+			foreach ( $user_ids as $user_id )
+				wp_cache_delete($user_id, 'user_meta');
+
+		return true;
+	}
+	return false;
+}
+
+/**
  * Remove user meta data.
  *
  * @since 2.0.0
@@ -455,6 +644,75 @@
 }
 
 /**
+ * Updates metadata cache for list of User IDs.
+ *
+ * Performs SQL query to retrieve the metadata for the User IDs and updates the
+ * metadata cache for the users. Therefore, the functions, which call this
+ * function, do not need to perform SQL queries on their own.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since xxx
+ *
+ * @uses $wpdb
+ *
+ * @param array $user_ids List of User IDs.
+ * @return bool|array Returns false if there is nothing to update or an array of metadata.
+ */
+function update_usermeta_cache($user_ids) {
+	global $wpdb;
+
+	if ( empty( $user_ids ) )
+		return false;
+
+	if ( !is_array($user_ids) ) {
+		$user_ids = preg_replace('|[^0-9,]|', '', $user_ids);
+		$user_ids = explode(',', $user_ids);
+	}
+
+	$user_ids = array_map('intval', $user_ids);
+
+	$ids = array();
+	foreach ( (array) $user_ids as $id ) {
+		if ( false === wp_cache_get($id, 'user_meta') )
+			$ids[] = $id;
+	}
+
+	if ( empty( $ids ) )
+		return false;
+
+	// Get user-meta info
+	$id_list = join(',', $ids);
+	$cache = array();
+	if ( $meta_list = $wpdb->get_results("SELECT user_id, meta_key, meta_value FROM $wpdb->usermeta WHERE user_id IN ($id_list)", ARRAY_A) ) {
+		foreach ( (array) $meta_list as $metarow) {
+			$mpid = (int) $metarow['user_id'];
+			$mkey = $metarow['meta_key'];
+			$mval = $metarow['meta_value'];
+
+			// Force subkeys to be array type:
+			if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
+				$cache[$mpid] = array();
+			if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
+				$cache[$mpid][$mkey] = array();
+
+			// Add a value to the current pid/key:
+			$cache[$mpid][$mkey][] = $mval;
+		}
+	}
+
+	foreach ( (array) $ids as $id ) {
+		if ( ! isset($cache[$id]) )
+			$cache[$id] = array();
+	}
+
+	foreach ( (array) array_keys($cache) as $user)
+		wp_cache_set($user, $cache[$user], 'user_meta');
+
+	return $cache;
+}
+
+/**
  * Create dropdown HTML content of users.
  *
  * The content can either be displayed, which it is by default or retrieved by
@@ -599,5 +857,3 @@
 	wp_cache_add($user->user_email, $user->ID, 'useremail');
 	wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
 }
-
-?>
