WordPress 用户魔法:wp_get_current_user()
函数源码深度剖析
大家好,我是你们今天的WordPress用户魔法师!今天要给大家揭秘一个WordPress世界里最常用的“咒语”之一:wp_get_current_user()
。 别看它短短几个字,蕴含的能量可不小,能帮你召唤出当前登录用户的全部信息。
废话不多说,我们直接进入正题,一起扒开它的源码,看看它到底施展了什么魔法,才能如此轻松地获取用户信息。
1. wp_get_current_user()
的基本用法与返回值
首先,我们来简单回顾一下wp_get_current_user()
的基本用法。在你的WordPress主题或插件中,只需要简单地调用这个函数:
<?php
$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) {
echo '当前没有用户登录';
} else {
echo '欢迎,' . $current_user->user_login . '!';
echo '你的邮箱是:' . $current_user->user_email;
}
?>
这段代码会检查当前是否有用户登录,如果有,就显示用户的用户名和邮箱。
wp_get_current_user()
函数的返回值是一个 WP_User
对象。如果没有用户登录,它会返回一个 ID
为 0 的 WP_User
对象。 也就是说,即使没有登录用户,你仍然能得到一个对象,只不过这个对象代表的是一个“匿名用户”。
返回值类型 | 说明 |
---|---|
WP_User |
如果有用户登录,返回包含用户信息的 WP_User 对象。 |
WP_User |
如果没有用户登录,返回 ID 为 0 的 WP_User 对象 (表示匿名用户)。 |
2. 源码追踪:从入口开始
现在,让我们深入到 WordPress 源码中,找到 wp-includes/pluggable.php
文件,这里是 wp_get_current_user()
函数的定义所在。
/**
* Gets the current logged-in user object.
*
* If the user is not logged in, then the return value will be 0.
*
* @since 2.0.0
* @since 3.5.0 Added `$deprecated` parameter.
* @since 4.5.0 `$deprecated` parameter marked as deprecated.
*
* @global WP_User|null $current_user
*
* @param mixed $deprecated Deprecated.
* @return WP_User Current user object, WP_User object on failure.
*/
function wp_get_current_user( $deprecated = '' ) {
global $current_user;
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '3.5.0' );
}
if ( isset( $current_user ) && ( $current_user instanceof WP_User ) ) {
/**
* Fires after the current user is set.
*
* @since 2.1.0
*
* @param WP_User $current_user WP_User object for the current user.
*/
do_action( 'set_current_user', $current_user );
return $current_user;
}
if ( function_exists( 'wp_set_current_user' ) ) {
wp_set_current_user();
} else {
$current_user = new WP_User( 0 );
}
/** This action is documented in wp-includes/pluggable.php */
do_action( 'set_current_user', $current_user );
return $current_user;
}
我们来逐行解读这段代码:
-
global $current_user;
这行代码声明了一个全局变量$current_user
。这个变量是用来存储当前登录用户的WP_User
对象的。重点来了,这是个全局变量,也就是说,在WordPress的很多地方都可以访问到它。 -
if ( ! empty( $deprecated ) ) { ... }
这部分代码是处理一个废弃参数$deprecated
的。从 WordPress 3.5.0 开始,这个参数就被标记为废弃,所以我们可以忽略它。 -
if ( isset( $current_user ) && ( $current_user instanceof WP_User ) ) { ... }
这是个关键的判断语句。它首先检查$current_user
变量是否已经被设置,并且是否是一个WP_User
对象。如果条件成立,说明当前用户的信息已经被加载过,直接返回$current_user
即可,避免重复加载。 -
do_action( 'set_current_user', $current_user );
如果用户已经存在,会触发set_current_user
这个 action hook。 插件或主题可以通过这个 hook 来执行一些与当前用户相关的操作,比如记录用户活动,更新用户统计信息等等。 -
if ( function_exists( 'wp_set_current_user' ) ) { ... }
如果$current_user
还没有被设置,它会检查wp_set_current_user()
函数是否存在。这个函数通常是在wp-includes/pluggable.php
中定义的(但也有可能被插件替换),负责加载当前用户的信息。 -
else { $current_user = new WP_User( 0 ); }
如果wp_set_current_user
函数不存在,说明WordPress可能还没有完全加载,或者出现了某些问题。在这种情况下,它会创建一个ID
为 0 的WP_User
对象,表示一个匿名用户。 -
do_action( 'set_current_user', $current_user );
无论用户是否已经存在,都会触发set_current_user
这个 action hook。 -
return $current_user;
最后,返回$current_user
对象。
3. wp_set_current_user()
函数的奥秘
现在,我们来重点看看 wp_set_current_user()
函数。它才是真正加载用户信息的幕后英雄。同样在 wp-includes/pluggable.php
文件中:
/**
* Sets the current user.
*
* @since 2.0.0
*
* @global WP_User|null $current_user
*
* @param int|string|WP_User $id User ID, User login, or WP_User object.
*/
function wp_set_current_user( $id = 0 ) {
global $current_user, $pagenow;
if ( ! ( $current_user instanceof WP_User ) ) {
$current_user = new WP_User();
}
if ( ! empty( $id ) ) {
$id = (int) $id;
} elseif ( is_admin() ) {
$id = wp_validate_auth_cookie();
} else {
$id = apply_filters( 'determine_current_user', false );
}
if ( ! $id ) {
$current_user = new WP_User( 0 );
return;
}
if ( $id != $current_user->ID ) {
$current_user->init( $id );
}
wp_cache_set( $current_user->ID, $current_user, 'users' );
}
我们来一行一行分析:
-
global $current_user, $pagenow;
声明全局变量$current_user
和$pagenow
。$pagenow
变量表示当前页面的名称,例如index.php
、edit.php
等。 -
if ( ! ( $current_user instanceof WP_User ) ) { ... }
如果$current_user
不是一个WP_User
对象,就创建一个新的WP_User
对象。 -
if ( ! empty( $id ) ) { ... }
如果传入了$id
参数,就将其转换为整数类型。这个$id
可以是用户 ID、用户名或WP_User
对象。 -
elseif ( is_admin() ) { ... }
如果在后台管理页面 (is_admin()
返回true
),就调用wp_validate_auth_cookie()
函数来验证用户的身份。这个函数会检查用户的登录 cookie,如果 cookie 有效,就返回用户 ID。 -
else { ... }
如果在前台页面,就使用apply_filters( 'determine_current_user', false )
来确定当前用户。这个 filter hook 允许插件或主题自定义用户身份验证逻辑。 -
if ( ! $id ) { ... }
如果$id
为空,说明无法确定当前用户,就创建一个ID
为 0 的WP_User
对象。 -
if ( $id != $current_user->ID ) { ... }
如果$id
与当前用户的 ID 不一致,就调用$current_user->init( $id )
方法来初始化用户信息。 -
wp_cache_set( $current_user->ID, $current_user, 'users' );
将当前用户的信息缓存到 WordPress 对象缓存中,方便下次快速获取。
4. wp_validate_auth_cookie()
:Cookie 验证的秘密
wp_validate_auth_cookie()
函数在后台用户身份验证中扮演着关键角色。它负责解析和验证用户的登录 cookie。 让我们来看看它的源码(位于 wp-includes/pluggable.php
中):
/**
* Validates authentication cookie.
*
* The cookie contains concatenated information: username, expiration timestamp,
* and hash. The username is plain text, the timestamp is base64 encoded,
* and the hash is a hash of the username, timestamp, password, and secret key.
* The secret key is dynamically generated when the user logs in, and is
* stored in the database.
*
* @since 2.5.0
*
* @param string $cookie Authentication cookie.
* @param string $scheme Authentication scheme. Default is 'auth'. Accepts
* 'auth', 'secure_auth', or 'logged_in'.
* @return int|false User ID if the cookie is valid, false otherwise.
*/
function wp_validate_auth_cookie( $cookie = '', $scheme = '' ) {
if ( ! $cookie ) {
switch ( $scheme ) {
case 'auth':
$cookie_name = AUTH_COOKIE;
break;
case 'secure_auth':
$cookie_name = SECURE_AUTH_COOKIE;
break;
case 'logged_in':
$cookie_name = LOGGED_IN_COOKIE;
break;
default:
$cookie_name = AUTH_COOKIE;
}
if ( empty( $_COOKIE[ $cookie_name ] ) ) {
return false;
}
$cookie = $_COOKIE[ $cookie_name ];
}
$cookie_elements = explode( '|', $cookie );
if ( count( $cookie_elements ) !== 4 ) {
return false;
}
list( $username, $expiration, $token, $hmac ) = $cookie_elements;
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
/**
* Fires after a cookie is validated.
*
* @since 5.1.0
*
* @param string $username Username from the cookie.
* @param int $expiration Expiration timestamp from the cookie.
* @param string $token Token from the cookie.
* @param string $hmac HMAC from the cookie.
* @param string $scheme Authentication scheme.
*/
do_action( 'auth_cookie_validation', $username, $expiration, $token, $hmac, $scheme );
}
$user = get_user_by( 'login', $username );
if ( ! $user ) {
return false;
}
$pass_frag = substr( $user->user_pass, 8, 4 );
$key = wp_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
$hash = hash_hmac( 'md5', $username . '|' . $expiration . '|' . $token, $key );
if ( hash_equals( $hmac, $hash ) ) {
if ( $expiration > time() ) {
return $user->ID;
} else {
/**
* Fires when a cookie is invalid because the expiration time has passed.
*
* @since 6.1.0
*
* @param WP_User $user WP_User object of the user corresponding to the cookie.
*/
do_action( 'auth_cookie_expired', $user );
}
}
return false;
}
这段代码的核心逻辑如下:
-
获取 Cookie: 首先,它会根据
$scheme
参数(auth
、secure_auth
或logged_in
)获取对应的 cookie 名称,并从$_COOKIE
数组中读取 cookie 的值。 -
解析 Cookie: Cookie 的值是一个字符串,由四个部分组成,用
|
分隔:用户名、过期时间戳、token 和 HMAC (Hash-based Message Authentication Code)。 -
验证用户: 根据用户名从数据库中获取用户信息。
-
生成 Hash: 使用用户名、密码片段、过期时间戳、token 和一个密钥(基于用户密码和 scheme 生成)来生成一个 HMAC。
-
比较 Hash: 将生成的 HMAC 与 cookie 中的 HMAC 进行比较。如果两者一致,说明 cookie 是有效的。
-
验证过期时间: 检查 cookie 的过期时间是否已过。如果过期时间未过,则返回用户 ID。
如果任何一个验证步骤失败,wp_validate_auth_cookie()
函数都会返回 false
。
5. WP_User
对象:用户信息的大本营
WP_User
类是 WordPress 中用于表示用户的核心类。它包含了用户的各种属性,例如 ID、用户名、邮箱、角色等等。 当 wp_get_current_user()
函数返回一个 WP_User
对象时,你就可以通过这个对象访问用户的各种信息。
WP_User
类的定义位于 wp-includes/class-wp-user.php
文件中。
class WP_User {
/**
* User data.
*
* @since 2.0.0
* @var stdClass
*/
public $data;
/**
* The user's ID.
*
* @since 2.1.0
* @access public
* @var int
*/
public $ID = 0;
/**
* The user's capabilities.
*
* @since 2.0.0
* @access public
* @var WP_User_Capabilities
*/
public $caps = array();
/**
* User metadata.
*
* @since 2.0.0
* @access public
* @var array
*/
public $meta = array();
/**
* The roles the user is part of.
*
* @since 2.0.0
* @access public
* @var array
*/
public $roles = array();
//... (省略其他方法)
}
你可以通过 WP_User
对象的属性来访问用户的各种信息,例如:
$current_user->ID
: 用户 ID$current_user->user_login
: 用户名$current_user->user_email
: 用户邮箱$current_user->roles
: 用户角色$current_user->caps
: 用户权限$current_user->data
: 包含了所有用户数据的stdClass
对象
6. 总结:wp_get_current_user()
的工作流程
现在,我们来总结一下 wp_get_current_user()
函数的工作流程:
- 检查全局变量
$current_user
是否已经存在。如果存在,并且是一个WP_User
对象,则直接返回$current_user
。 - 如果
$current_user
不存在,则调用wp_set_current_user()
函数来加载当前用户的信息。 wp_set_current_user()
函数会根据当前环境(后台或前台)来确定用户 ID。- 在后台,它会使用
wp_validate_auth_cookie()
函数来验证用户的登录 cookie。 - 在前台,它会使用
apply_filters( 'determine_current_user', false )
filter hook 来确定用户 ID。
- 在后台,它会使用
wp_set_current_user()
函数会创建一个WP_User
对象,并将用户的信息加载到这个对象中。wp_set_current_user()
函数会将WP_User
对象缓存到 WordPress 对象缓存中。wp_get_current_user()
函数返回$current_user
对象。
7. 实际应用:一些有趣的例子
现在,让我们来看一些实际应用 wp_get_current_user()
函数的例子:
-
根据用户角色显示不同的内容:
<?php $current_user = wp_get_current_user(); if ( in_array( 'administrator', $current_user->roles ) ) { echo '欢迎管理员!你可以访问所有功能。'; } elseif ( in_array( 'editor', $current_user->roles ) ) { echo '欢迎编辑!你可以编辑和发布文章。'; } else { echo '欢迎!你可以阅读文章。'; } ?>
-
只允许登录用户访问特定页面:
<?php if ( ! is_user_logged_in() ) { wp_redirect( wp_login_url( get_permalink() ) ); exit; } ?>
-
在用户个人资料页面显示用户的自定义元数据:
<?php $current_user = wp_get_current_user(); $favorite_color = get_user_meta( $current_user->ID, 'favorite_color', true ); if ( ! empty( $favorite_color ) ) { echo '你最喜欢的颜色是:' . $favorite_color; } ?>
8. 注意事项:一些小贴士
- 不要滥用
wp_get_current_user()
: 虽然wp_get_current_user()
函数非常方便,但不要在每个页面都调用它。频繁调用会增加数据库查询的次数,影响网站的性能。尽量将用户信息缓存起来,避免重复加载。 - 注意用户权限: 在使用用户信息时,一定要注意用户的权限。不要让用户访问他们不应该访问的内容或功能。
- 使用
is_user_logged_in()
函数: 如果你只需要检查用户是否登录,而不需要获取用户信息,可以使用is_user_logged_in()
函数。这个函数比wp_get_current_user()
函数更轻量级。 - 利用
determine_current_user
filter hook: 如果你需要自定义用户身份验证逻辑,可以使用determine_current_user
filter hook。
9. 总结
wp_get_current_user()
函数是 WordPress 中一个非常重要的函数,它可以帮助你轻松地获取当前登录用户的全部信息。 通过深入了解它的源码,你可以更好地理解 WordPress 的用户管理机制,并能够更灵活地使用用户信息。
希望今天的讲座能够帮助你掌握 wp_get_current_user()
函数的魔法,在你的 WordPress 项目中大放异彩! 记住,理解源码是成为 WordPress 大师的关键一步!
谢谢大家!