好的,我们开始今天的讲座,主题是:wp_update_user
如何与 usermeta
同步写入逻辑。
wp_update_user
是 WordPress 提供的一个核心函数,用于更新用户信息。 用户信息不仅仅包含基本的 wp_users
表中的字段,还包括大量的用户元数据(usermeta
),存储在 wp_usermeta
表中。 理解 wp_update_user
如何与 usermeta
协同工作对于开发涉及用户管理的 WordPress 插件或主题至关重要。
1. wp_update_user
函数概述
wp_update_user
函数位于 wp-includes/user.php
文件中。 它的基本语法如下:
/**
* Updates user data.
*
* @since 2.0.0
*
* @param array|WP_User|object $userdata User ID or array of user data.
* @return int|WP_Error WP_Error on failure, User ID on success.
*/
function wp_update_user( $userdata ) {
global $wpdb;
$user = null;
if ( is_object( $userdata ) ) {
$userdata = (array) $userdata;
}
if ( is_numeric( $userdata ) ) {
$user_id = $userdata;
$userdata = array( 'ID' => $user_id );
} else {
$user_id = isset( $userdata['ID'] ) ? absint( $userdata['ID'] ) : 0;
}
if ( ! $user_id ) {
return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
}
$user = get_user( $user_id );
if ( ! $user ) {
return new WP_Error( 'invalid_user', __( 'Invalid user.' ) );
}
$data = wp_unslash( $userdata ); // Unslash incoming data.
// Core fields.
$update = array();
if ( isset( $data['user_pass'] ) ) {
$update['user_pass'] = wp_hash_password( $data['user_pass'] );
}
if ( isset( $data['user_login'] ) ) {
$update['user_login'] = $data['user_login'];
}
if ( isset( $data['user_nicename'] ) ) {
$update['user_nicename'] = sanitize_title_with_dashes( $data['user_nicename'], '', 'save' );
}
if ( isset( $data['user_url'] ) ) {
$update['user_url'] = esc_url_raw( $data['user_url'] );
}
if ( isset( $data['user_email'] ) ) {
$update['user_email'] = sanitize_email( $data['user_email'] );
}
if ( isset( $data['display_name'] ) ) {
$update['display_name'] = trim( $data['display_name'] );
}
if ( isset( $data['nickname'] ) ) {
$update['nickname'] = trim( $data['nickname'] );
}
if ( isset( $data['first_name'] ) ) {
$update['first_name'] = trim( $data['first_name'] );
}
if ( isset( $data['last_name'] ) ) {
$update['last_name'] = trim( $data['last_name'] );
}
if ( isset( $data['description'] ) ) {
$update['description'] = trim( $data['description'] );
}
if ( isset( $data['locale'] ) ) {
$update['locale'] = sanitize_text_field( $data['locale'] );
}
// Fires before the user profile is updated.
do_action( 'profile_update', $user_id, $data );
if ( ! empty( $update ) ) {
$where = array( 'ID' => $user_id );
$updated = $wpdb->update( $wpdb->users, $update, $where );
if ( false === $updated ) {
return new WP_Error( 'db_update_error', __( 'Could not update user in database.' ), $wpdb->last_error );
}
}
// Update user meta.
if ( isset( $data['meta'] ) && is_array( $data['meta'] ) ) {
foreach ( $data['meta'] as $key => $value ) {
update_user_meta( $user_id, $key, $value );
}
} else {
// Handle individual usermeta updates.
$allowed_meta_keys = apply_filters( 'update_user_meta_keys', array() );
foreach ( $data as $key => $value ) {
if ( in_array( $key, $allowed_meta_keys, true ) ) {
update_user_meta( $user_id, $key, $value );
}
}
}
clean_user_cache( $user_id );
// Fires after the user profile is updated.
do_action( 'updated_user', $user_id, $data );
return $user_id;
}
该函数接收一个数组或对象作为参数,其中包含要更新的用户数据。 它可以更新 wp_users
表中的核心字段(例如 user_pass
, user_email
, display_name
), 并能通过 update_user_meta
函数更新 wp_usermeta
表中的用户元数据。
2. wp_usermeta
表结构
wp_usermeta
表用于存储用户的元数据。 它的基本结构如下:
列名 | 数据类型 | 说明 |
---|---|---|
umeta_id | bigint(20) UNSIGNED | 主键,自增长 |
user_id | bigint(20) UNSIGNED | 关联的用户的 ID,外键,指向 wp_users.ID |
meta_key | varchar(255) | 元数据的键名 |
meta_value | longtext | 元数据的值 |
3. update_user_meta
函数
update_user_meta
函数负责更新或添加用户的元数据。 它的基本语法如下:
/**
* Updates user meta field based on user ID.
*
* Use the is_protected_meta() function to check whether the key provided
* is protected and to prevent updating protected meta.
*
* @since 2.9.0
*
* @param int $user_id User ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. May be an array or object.
* @param mixed $prev_value Optional. Previous value to check before removing.
* If specified, only delete rows matching when updating.
*
* @return int|bool False on failure, true if value did not change, otherwise the number of rows affected.
*/
function update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' ) {
return update_metadata( 'user', $user_id, $meta_key, $meta_value, $prev_value );
}
update_user_meta
函数实际上是调用了更通用的 update_metadata
函数,该函数可以用于更新各种类型的元数据(包括 post meta, term meta 等)。
4. wp_update_user
与 update_user_meta
的同步逻辑
wp_update_user
函数内部直接调用了 update_user_meta
函数来处理用户元数据的更新。 具体逻辑如下:
-
数据准备: 首先,
wp_update_user
函数接收传入的用户数据,并从中提取出核心字段和元数据。 -
核心字段更新: 函数更新
wp_users
表中的核心字段,例如user_email
和display_name
。 -
元数据更新: 函数检查传入的数据中是否包含
meta
键。 如果包含,则遍历meta
数组,并为每个键值对调用update_user_meta
函数。- 如果没有
meta
键,则检查传入的数据中是否存在允许更新的元数据键。 这通过apply_filters( 'update_user_meta_keys', array() )
实现,允许插件或主题定义哪些键可以直接通过wp_update_user
更新。
- 如果没有
-
update_user_meta
执行:update_user_meta
函数接收用户 ID、元数据键名和元数据值作为参数。 它内部的update_metadata
函数执行以下操作:- 检查是否存在: 首先,查询
wp_usermeta
表中是否存在user_id
和meta_key
匹配的记录。 - 更新或添加:
- 如果存在匹配的记录,则更新
meta_value
字段。 - 如果不存在匹配的记录,则插入一条新的记录,包含
user_id
,meta_key
和meta_value
。
- 如果存在匹配的记录,则更新
- 可选的
prev_value
参数:update_user_meta
允许传入一个可选的$prev_value
参数。 如果指定了该参数,则只有在数据库中已存在的meta_value
与$prev_value
相匹配时,才会执行更新操作。 这可以用于防止并发更新导致的数据丢失。 - 数据序列化:
update_metadata
函数会自动序列化(serialize)数组和对象类型的meta_value
,以便将其存储在wp_usermeta
表的longtext
字段中。 读取时,会自动反序列化(unserialize)。
- 检查是否存在: 首先,查询
-
清理缓存:
wp_update_user
函数在更新完成后,会调用clean_user_cache
函数清理用户缓存,以确保后续访问的用户信息是最新的。 -
触发 Action Hooks:
wp_update_user
在更新之前和之后分别触发profile_update
和updated_user
action hooks,允许插件或主题在用户更新过程中执行自定义逻辑。
5. 代码示例
以下是一个示例,演示如何使用 wp_update_user
函数更新用户的核心字段和元数据:
$user_id = 1; // 要更新的用户的 ID
$userdata = array(
'ID' => $user_id,
'user_email' => '[email protected]',
'display_name' => 'New Display Name',
'meta' => array(
'phone' => '123-456-7890',
'address' => '123 Main Street'
)
);
$result = wp_update_user( $userdata );
if ( is_wp_error( $result ) ) {
echo 'Error updating user: ' . $result->get_error_message();
} else {
echo 'User updated successfully. User ID: ' . $result;
}
在这个示例中,我们更新了用户的 user_email
和 display_name
字段,并添加了 phone
和 address
两个元数据。
6. 使用 update_user_meta_keys
filter
可以通过 update_user_meta_keys
filter 允许直接通过 wp_update_user
更新指定的元数据键,而无需将它们放入 meta
数组。
add_filter( 'update_user_meta_keys', 'my_allowed_meta_keys' );
function my_allowed_meta_keys( $allowed_meta_keys ) {
$allowed_meta_keys[] = 'custom_field_1';
$allowed_meta_keys[] = 'custom_field_2';
return $allowed_meta_keys;
}
// 现在可以直接这样更新:
$userdata = array(
'ID' => 1,
'custom_field_1' => 'value 1',
'custom_field_2' => 'value 2'
);
wp_update_user( $userdata );
7. 使用 profile_update
和 updated_user
action hooks
profile_update
和 updated_user
action hooks 允许在用户更新过程中执行自定义逻辑。
add_action( 'profile_update', 'my_profile_update_action', 10, 2 );
function my_profile_update_action( $user_id, $old_user_data ) {
// 在用户更新之前执行的逻辑
// 例如,记录日志或发送通知
error_log( 'User ' . $user_id . ' is being updated.' );
error_log( print_r( $old_user_data, true ) ); // 打印旧的用户数据
}
add_action( 'updated_user', 'my_updated_user_action', 10, 2 );
function my_updated_user_action( $user_id, $user_data ) {
// 在用户更新之后执行的逻辑
// 例如,更新其他相关数据或发送确认邮件
error_log( 'User ' . $user_id . ' updated successfully.' );
error_log( print_r( $user_data, true ) ); // 打印新的用户数据
}
8. 安全注意事项
- 数据验证和清理: 在更新用户信息之前,务必对所有传入的数据进行验证和清理,以防止安全漏洞,例如 SQL 注入和跨站脚本攻击 (XSS)。 使用
sanitize_email
,esc_url_raw
,sanitize_text_field
等函数来清理数据。 - 权限控制: 确保只有授权的用户才能更新用户信息。 使用
current_user_can
函数检查当前用户是否具有相应的权限。 - 防止恶意元数据: 限制可以更新的元数据键,并对元数据值进行验证,以防止恶意用户存储恶意数据。 考虑使用
update_user_meta_keys
filter 来限制可更新的键。
9. 常见的 usermeta
键
以下是一些常见的 usermeta
键:
键名 | 说明 |
---|---|
nickname | 昵称 |
first_name | 名 |
last_name | 姓 |
description | 个人简介 |
rich_editing | 是否使用可视化编辑器 |
comment_shortcuts | 是否启用评论快捷键 |
admin_color | 管理后台配色方案 |
show_admin_bar_front | 是否在前台显示管理工具栏 |
wp_capabilities | 用户角色和权限 |
wp_user_level | 用户级别 |
这些只是示例, 插件和主题可以根据需要添加自定义的元数据键。
10. 总结
wp_update_user
函数通过直接调用 update_user_meta
函数来同步更新核心用户信息以及用户元数据。 理解 update_user_meta
的工作原理以及如何使用 update_user_meta_keys
filter 和 action hooks 对于有效地管理 WordPress 用户信息至关重要。 务必注意数据验证和安全,以确保用户数据的完整性和安全性。