众所周知,大部分WordPress的主题不带修改用户邮箱的功能,想要修改用户绑定的邮箱,需要进入网站后台个人资料中进行修改,而且恕我直言,WordPress修改邮箱有点不人性化的,就像我当开始修改邮箱的时候一脸懵。
后来才发现原来要保存,并不是常规的点击按钮,弹出窗口输出新邮箱,点击提交,然后验证邮箱就行的操作。
但是不是所有的主题都支持常规用户进入后台,那么绑定的邮箱是不是就无法修改了呢?
其实不完全对,我们可以对WordPress主题增加用户修改邮箱的功能,让注册用户在登录后,进入到个人中心进行修改。
当然,如果你说WordPress主题中也没有用户中心,那我真的就只能表示爱莫能助了。
PS:这里建议使用Puock主题,真的很赞。
废话不多说,我们直接进入实现的简单方法,以Puock主题为例:
修改用户中心代码
首先,我们找到用户中心的代码所在位置,编辑代码。
wordpress-theme-puock/inc/classes/PuockUserCenter.php
找到以下代码:
private static function register_basic_menus()
{
self::$menus['profile'] = [
'title' => __('个人资料', PUOCK),
'subtitle' => __('您的基本个人资料', PUOCK),
'call' => array(__CLASS__, 'page_profile'),
];
}
这段代码不用做修改,找到他的目的只是为了找到“page_profile”回调函数,这里意味着,回调函数所属的代码就是用户中心的个人资料页面代码。
根据上面的回调函数"page_profile"找到下面这段代码:
public static function page_profile()
{
$userinfo = get_userdata(get_current_user_id());
?>
<form action="<?php echo pk_ajax_url('pk_user_update_profile') ?>" class="ajax-form" data-no-reset>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">ID</label>
<div class="col-sm-10">
<input type="text" readonly class="form-control" value="<?php echo $userinfo->ID ?>">
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">用户名</label>
<div class="col-sm-10">
<input type="text" readonly class="form-control" value="<?php echo $userinfo->user_nicename ?>">
<small class="c-sub">用户名不可更改</small>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">昵称</label>
<div class="col-sm-10">
<input name="nickname" type="text" class="form-control" value="<?php echo $userinfo->nickname ?>">
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">网站地址</label>
<div class="col-sm-10">
<input name="user_url" type="url" class="form-control" value="<?php echo $userinfo->user_url ?>">
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">个人说明</label>
<div class="col-sm-10">
<textarea name="description" class="form-control"
rows="4"><?php echo $userinfo->description ?></textarea>
</div>
</div>
<div class="mb-3 text-center">
<button class="btn btn-primary btn-sm" type="submit">提交保存</button>
</div>
</form>
<?php
}
我们要对上面这段代码进行修改。
在用户名或者昵称的下面增加这段代码:
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">绑定邮箱</label>
<div class="col-sm-10">
<div class="row align-items-center">
<div class="col-6">
<input type="text" readonly class="form-control" value="<?php echo $userinfo->user_email ?>">
</div>
<div class="col-6 d-flex">
<button id="change-email-btn" class="btn btn-primary btn-sm" type="button">更换邮箱</button>
</div>
</div>
</div>
</div>
<div id="change-email" style="display: none;">
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">新邮箱地址</label>
<div class="col-sm-10">
<div class="row align-items-center">
<div class="col-6">
<input name="new_email" type="email" class="form-control" placeholder="请输入新邮箱地址">
</div>
<div class="col-6 d-flex">
<button id="submit-email" class="btn btn-primary btn-sm" type="button">提交更改</button>
</div>
</div>
</div>
</div>
</div>
然后在代码尾部的</form>
和<?php
中间,增加下面这段代码:
<script>
jQuery(function($) {
$('#change-email-btn').on('click', function() {
$('#change-email').toggle();
});
$('#submit-email').on('click', function() {
var newEmail = $('input[name="new_email"]').val();
if (newEmail) {
$.ajax({
url: '<?php echo pk_ajax_url('pk_user_update_email') ?>',
type: 'POST',
data: {
new_email: newEmail,
action: 'pk_user_update_email',
security: '<?php echo wp_create_nonce('pk-update-email-nonce'); ?>'
},
success: function(response) {
if (response.success) {
// alert(response.data.message);
window.Puock.toast(response.data.message, TYPE_SUCCESS);
} else {
// alert(response.data.message);
window.Puock.toast(response.data.message, TYPE_DANGER);
}
},
error: function(xhr, status, error) {
console.error(xhr.responseText);
}
});
} else {
window.Puock.toast('请输入新邮箱地址', TYPE_DANGER);
}
});
});
</script>
上面这段JS的意思简单解释:
1、$('#change-email-btn').on('click', function() { ... })
:绑定点击事件,点击“更换邮箱”按钮时,打开“新邮箱地址”输入框。
2、$('#submit-email').on('click', function() { ... })
:绑定点击事件,点击“提交更改”按钮时,执行内部函数。
3、var newEmail = $('input[name="new_email"]').val();
:获取表单中名为new_email
框的值,就是新邮箱地址。
4、通过$.ajax({ ... })
发起了一个 AJAX 请求,其中,url: '<?php echo pk_ajax_url('pk_user_update_email') ?>'
指定了 AJAX 请求的目标 URL,这里是一个 PHP 函数 pk_ajax_url() 的返回值,用于处理用户更新邮箱的请求。
5、type: 'POST'
:指定了请求的 HTTP 方法为 POST。
6、data: { ... }
:设置了要发送到服务器的数据。其中包括了新邮箱地址 new_email、动作标识 action、以及一个安全性验证参数 security。
7、success: function(response) { ... }
:定义了请求成功时的回调函数。
8、error: function(xhr, status, error) { ... }
:定义了请求失败时的回调函数。
9、window.Puock.toast()
:为了适配Puock主题的提示方式。
增加AJAX处理回调函数
将下面这段代码添加到主题的functions.php
文件尾部,如果有子主题,可以添加到子主题的functions.php
文件中。
//更换邮箱
add_action('wp_ajax_pk_user_update_email', 'pk_user_update_email_callback');
function pk_user_update_email_callback() {
check_ajax_referer('pk-update-email-nonce', 'security');
// 验证用户是否已登录
if (!is_user_logged_in()) {
wp_send_json_error(array('message' => '请先登录'));
}
$newEmail = isset($_POST['new_email']) ? sanitize_email($_POST['new_email']) : '';
if (!is_email($newEmail)) {
wp_send_json_error(array('message' => '请输入有效的邮箱地址'));
}
$userinfo = wp_get_current_user();
$userId = $userinfo->ID;
$oldEmail = $userinfo->user_email;
if ($newEmail === $oldEmail) {
wp_send_json_error(array('message' => '邮箱与原邮箱相同'));
}
$site_title = get_bloginfo('name'); // 获取网站标题
$site_url = get_site_url(); // 获取网站URL
$username = wp_get_current_user()->user_login; // 获取用户名
// 检查邮箱是否已被其他用户绑定
$users_with_email = get_user_by('email', $newEmail);
if ($users_with_email && $users_with_email->ID !== $userId) {
// 如果其他用户已经绑定了该邮箱,则返回拒绝信息
wp_send_json_error(array('message' => '邮箱已被其他用户绑定'));
}
// 生成确认密钥
$confirmation_key = wp_generate_password(50, false);
// 设置到期时间(例如,5分钟后)
$expiry_timestamp = time() + (5 * 60); // 有效期为5分钟
// 将到期时间存储到用户的元数据中
update_user_meta($userId, 'email_confirmation_expiry', $expiry_timestamp);
update_user_meta($userId, 'email_confirmation_key', $confirmation_key); // 将确认密钥存储到用户的元数据中
update_user_meta($userId, 'email_confirmation_newmail', $newEmail); // 将新邮箱存储到用户的元数据中
update_user_meta($userId, 'email_confirmation_userid', $userId); // 将用户ID存储到用户的元数据中
// 发送确认邮件
$subject = '['.$site_title.'] 电子邮箱地址变更请求';
$confirmation_link = add_query_arg(array('u'=>$userId,'key' => $confirmation_key), get_permalink(get_page_by_path('email-confirmation')));
$message = "<div style=\"font-size: 14px; font-family: Arial, sans-serif;\">
<p>您好, $username</p>
<p>您最近请求修改您账户的电子邮箱地址。</p>
<p>如果您确实要修改,请点击以下链接:<br />
<a href=\"$confirmation_link\">$confirmation_link</a></p>
<p>注意:链接有效期为:5分钟,超时请重新提交请求。</p>
<p>如果您并未请求修改,则可安全的忽视并删除此邮件。</p>
<p>此邮件被发送至 $newEmail</p>
<p>祝好,<br>$site_title 全体成员敬上</p>
<p><a href=\"$site_url\">$site_title</a></p>
</div>";
$headers[] = 'Content-Type: text/html; charset=UTF-8';
$send_email = wp_mail($newEmail, $subject, $message, $headers);
if ($send_email) {
wp_send_json_success(array('message' => '邮件发送成功,请注意查收', 'expiry_timestamp' => $expiry_timestamp));
} else {
wp_send_json_error(array('message' => '邮件发送失败,请稍后重试'));
}
wp_die();
}
上面这段PHP的意思简单解释:
1、add_action('wp_ajax_pk_user_update_email', 'pk_user_update_email_callback');
:这行代码将函数pk_user_update_email_callback
注册为一个 AJAX 动作处理器。当 AJAX 请求中的动作参数为pk_user_update_email
时,WordPress 将调用此函数处理请求。
2、function pk_user_update_email_callback() { ... }
:这是处理 AJAX 请求的函数的定义。
3、check_ajax_referer('pk-update-email-nonce', 'security');
:这行代码检查AJAX请求中的安全性验证参数,以确保请求是合法的。pk-update-email-nonce
是用于验证的 nonce(一次性令牌),用于防止 CSRF(跨站请求伪造)攻击。
4、if (!is_user_logged_in()) { ... }
:这段代码检查用户是否已登录。
5、$newEmail = isset($_POST['new_email']) ? sanitize_email($_POST['new_email']) : '';
:这行代码获取并清理 AJAX 请求中的新邮箱地址,并将其存储在 $newEmail 变量中。
6、if (!is_email($newEmail)) { ... }
:这段代码检查新邮箱地址的格式是否有效。
7、$userinfo = wp_get_current_user();
:这行代码获取当前用户的信息,包括用户ID和当前邮箱地址。
8、if ($newEmail === $oldEmail) { ... }
:这段代码检查新邮箱地址是否与当前邮箱地址相同。
9、$users_with_email = get_user_by('email', $newEmail);
:这行代码检查新邮箱地址是否已被其他用户绑定。
10、wp_generate_password(50, false)
:生成一个长度为 50 个字符的随机密码作为确认密钥。
11、time() + (5 * 60)
:计算出到期时间,这里设置为当前时间加上 5 分钟。
12、update_user_meta();
存储到用户的元数据中,以便后续验证和处理。
13、后面的一段是用来构建确认邮件内容,包括确认链接、提示信息等。
14、wp_mail()
:发送确认邮件到用户提供的新邮箱地址。
15、if ($send_email) { ... }
:根据发送邮件的结果,返回相应的成功或失败消息。
16、wp_die();
:这行代码确保在处理完 AJAX 请求后结束脚本的执行,以防止额外的输出。
验证用户邮箱地址
在主题pages
目录下新建名为email-confirmation-template.php
的文件并复制以下代码粘贴到其中,如果有子主题,可以在子主题的pages
目录下新建。
<?php
/*
Template Name: 邮箱更换模板
*/
// 获取确认链接中的参数
$confirmation_key = isset($_GET['key']) ? $_GET['key'] : '';
$user_id = isset($_GET['u']) ? $_GET['u'] : '';
// 确认链接参数存在时执行以下操作
if ($confirmation_key) {
// 获取用户的邮箱确认信息
$stored_key = get_user_meta($user_id, 'email_confirmation_key', true);
$expiry_timestamp = get_user_meta($user_id, 'email_confirmation_expiry', true);
$new_email = get_user_meta($user_id, 'email_confirmation_newmail', true);
$stored_user_id = get_user_meta($user_id, 'email_confirmation_userid', true);
// 验证确认链接的有效性
if ($confirmation_key === $stored_key && $expiry_timestamp && $expiry_timestamp > time() && $stored_user_id == $user_id) {
// 更新用户邮箱地址
$update_email = wp_update_user(array('ID' => $stored_user_id, 'user_email' => $new_email));
// 邮箱地址更新成功
if (!is_wp_error($update_email)) {
// 删除确认密钥和到期时间
delete_user_meta($stored_user_id, 'email_confirmation_key');
delete_user_meta($stored_user_id, 'email_confirmation_expiry');
delete_user_meta($stored_user_id, 'email_confirmation_newmail');
delete_user_meta($stored_user_id, 'email_confirmation_userid');
// 显示确认成功消息
$success_message = '邮箱地址已成功更改为' . $new_email;
echo '<div class="confirmation-message">' . $success_message . '</div>';
} else {
// 显示确认失败消息
$error_message = '邮箱地址更改失败,请联系管理员';
echo '<div class="error-message">' . $error_message . '</div>';
}
} elseif ($stored_user_id != $user_id) {
// 显示用户ID不匹配消息
$invalid_id_message = '用户ID不匹配,禁止修改他人账户。';
echo '<div class="error-message">' . $invalid_id_message . '</div>';
} elseif ($expiry_timestamp <= time()) {
// 显示确认链接已过期消息
$expired_message = '链接已过期,请重新发起请求。';
echo '<div class="error-message">' . $expired_message . '</div>';
// 清除过期的元数据
delete_user_meta($user_id, 'email_confirmation_key');
delete_user_meta($user_id, 'email_confirmation_expiry');
delete_user_meta($user_id, 'email_confirmation_newmail');
delete_user_meta($user_id, 'email_confirmation_userid');
} else {
// 显示确认链接无效消息
$invalid_message = '链接无效,请确认您的请求。';
echo '<div class="error-message">' . $invalid_message . '</div>';
}
} else {
// 显示无效请求消息
$invalid_request_message = '无效的请求,请提供确认密钥。';
echo '<div class="error-message">' . $invalid_request_message . '</div>';
}
?>
上面这段PHP的意思简单解释:
1、$confirmation_key = isset($_GET['key']) ? $_GET['key'] : '';
和$user_id = isset($_GET['u']) ? $_GET['u'] : '';
:这两行代码分别获取 URL 参数中的确认密钥和用户ID。
2、$confirmation_key
:存在时,表示有确认链接参数传递过来,执行以下操作。
3、get_user_meta()
:函数获取用户的元数据,包括确认密钥、到期时间、新邮箱地址和用户 ID。
4、然后是一系列的判断,检查确认密钥是否与存储的密钥匹配,并且确认链接是否过期,验证存储的用户 ID 是否与传递的用户 ID 匹配。
5、如果确认链接有效且都成功匹配,则执行wp_update_user()
函数更新用户的邮箱地址。
6、如果邮箱地址更新成功,删除确认密钥和到期时间的元数据,并返回成功消息,否则返回失败消息。
7、如果确认链接无效,根据不同的情况显示相应的错误消息,如链接过期、ID不匹配等。
WordPress增加页面
进入WordPress后台,在页面中增加一个页面,模板选择“邮箱更换模板”,别名改为email-confirmation
然后保存模板。
到此,应该就可以在用户中心修改用户绑定邮箱了!
以上代码可能会存在错误,如有,请在留言区域反馈,我们一起进行改进、
共计15人点赞,其中2人来自小程序