如何在WordPress用户资料更新邮件通知中同时获取新旧用户信息、解决通知重复
1. 钩子注册参数配置错误
WordPress profile_update 钩子触发时,会依次传入3个参数:用户ID(整数)、更新前的旧用户对象(WP_User)、本次更新的字段映射数组。
你当前调试时打印$olduserdata返回1,本质是注册钩子时没有指定回调可接收的参数数量——WordPress默认只给回调传1个参数,根本收不到后续的旧用户对象数据。
正确的钩子注册必须显式声明接收3个参数:
add_action( 'profile_update', 'user_profile_update', 10, 3 );
末尾的3参数不可缺失,缺少时所有后续形参都会赋值为空,这是你拿不到旧数据的核心原因。
2. 旧数据获取逻辑完全错误
钩子已经将完整的旧用户对象作为第二个参数传入,无需额外调用get_userdata()获取。
你当前写的$user_info_old = get_userdata( $olduserdata )存在根本性逻辑错误:get_userdata()只接受数字用户ID作为入参,你直接传入WP_User对象,自然返回空值,导致后续读取$user_info_old->discord_id全为空。
3. 代码执行顺序错误
你在代码开头就调用wc_memberships_get_user_memberships( $user_info, $args ),但此时$user_info尚未赋值,$args也未初始化,这行调用无法返回有效会员数据。
4. 自定义字段读取方式错误
你当前直接用$user_info->discord_id读取自定义字段值,这是拿不到最新数据的核心原因。WP_User对象仅内置基础用户字段(如登录名、邮箱),自定义存储的discord_id字段不会自动挂载到对象属性上,直接读取属性会拿到对象缓存中的旧值,必须通过get_user_meta()接口取值。
5. 邮件重复发送的原因
该现象不是WordPress重复调用钩子导致,常见触发场景包括:
- 同一请求内多次执行
wp_update_user():WooCommerce、WooCommerce Memberships这类插件,会在用户保存资料时分多次更新不同维度的用户数据,每一次更新都会触发一次profile_update钩子 - 插件重复注册了同一个回调函数
- 钩子执行过程中逻辑分支多次触发
wp_mail()
// 注册钩子时显式声明接收3个入参 add_action( 'profile_update', 'user_profile_update', 10, 3 ); function user_profile_update( $user_id, $old_user_data, $update_args ) { // 请求内防重复锁,避免同一请求多次执行发信 static $executed_user_ids = []; if ( in_array( $user_id, $executed_user_ids ) ) { return; } $executed_user_ids[] = $user_id; // 清理用户缓存,确保拿到最新用户数据 clean_user_cache( $user_id ); $user_info = get_userdata( $user_id ); // 读取更新前的旧discord_id $old_discord_id = get_user_meta( $user_id, 'discord_id', true ); // 读取更新后的新discord_id $new_discord_id = get_user_meta( $user_id, 'discord_id', true ); // 初始化会员查询 $active_memberships = wc_memberships_get_user_memberships( $user_id ); if ( ! $active_memberships || ! $new_discord_id ) { return; } $namemembership = $active_memberships[0]->plan->name; $user_regdate = date( 'm/d/Y h:s', strtotime( $user_info->user_registered ) ); $to = 'xxxxx@zapiermail.com'; $subject = $new_discord_id; $message = "**Name: **".$user_info->user_firstname." ".$user_info->user_lastname. "\n**Email Address: **" .$user_info->user_email. "\n**Membership: **".$namemembership."\n**Registered: **".$user_regdate." UTC\n更新前Discord ID: ".$old_discord_id."\n更新后Discord ID: ```".$new_discord_id."```\n请确认配置对应权限、移除已验证标签。"; wp_mail( $to, $subject, $message); }
- 无需额外叠加复杂的缓存清理逻辑,在读取新数据前执行一次
clean_user_cache($user_id)即可从数据库同步最新值 - 所有自定义用户字段必须通过
get_user_meta()读取,不要依赖WP_User对象的自定义属性,否则极易拿到缓存中的旧值 - 旧数据不需要额外存储到自定义表,钩子传入的
$old_user_data已经包含更新前的完整用户基础信息,配合用户meta接口即可拿到对应字段的旧值
内容的提问来源于stack exchange,提问作者Thomas Löw

