剖析 WordPress `wp_new_user_notification()` 函数的源码:如何发送新用户注册通知邮件。

各位观众老爷们,欢迎来到今天的“WordPress源码解剖”讲座。今天咱们要扒的是WordPress里一个非常重要但又容易被忽略的函数:wp_new_user_notification()。这玩意儿负责给新注册的用户和管理员发送邮件,告诉他们“嘿,有人来了!”。

咱们不搞虚的,直接上干货,从源码入手,看看这货到底是怎么运作的。

1. 函数的定义和基本结构

首先,我们找到wp-includes/pluggable.php文件,这个文件里面藏着很多WordPress核心的可插拔函数,wp_new_user_notification()就在其中。

/**
 * Sends notification email to admin and new user when a new user is created.
 *
 * @since 2.0.0
 *
 * @param int    $user_id       User ID.
 * @param string $notify        Optional. Type of notification that should happen. Accepts 'admin', 'user', or empty
 *                              string (admin and user). Default empty string.
 * @param string $deprecated    Optional. Deprecated in 4.3.0.
 */
function wp_new_user_notification( $user_id = 0, $notify = '', $deprecated = '' ) {
    //... 函数体
}

简单解释一下:

  • $user_id:新注册用户的ID,这是必须的。
  • $notify:通知类型,可以设置成 'admin'(只通知管理员),'user'(只通知用户),或者留空(两者都通知)。
  • $deprecated:一个被废弃的参数,不用管它。

2. 参数处理和用户数据获取

函数的第一步是处理参数,并获取用户的相关信息。

    global $wpdb, $wp_hasher;

    if ( empty( $notify ) ) {
        $notify = 'both';
    }

    $user = get_userdata( $user_id );

    if ( ! $user ) {
        return;
    }

    $user_login = stripslashes( $user->user_login );
    $user_email = stripslashes( $user->user_email );
    $key = '';

这里做了几件事:

  • 定义了全局变量 $wpdb (数据库连接) 和 $wp_hasher (密码哈希)。
  • 如果 $notify 为空,默认设置为 'both',表示管理员和用户都要通知。
  • 使用 get_userdata() 函数通过 $user_id 获取用户数据,如果找不到用户,直接 return,结束函数。
  • 从用户数据中提取用户名 ($user_login) 和邮箱 ($user_email),并使用 stripslashes() 函数去除转义字符,保证数据的干净。

3. 生成激活密钥 (如果需要)

如果启用了用户注册,并且用户需要激活账号,那么就需要生成一个激活密钥。

    if ( 'user' === $notify || 'both' === $notify ) {
        // Generate something random for a key...
        if ( empty( $wp_hasher ) ) {
            require_once ABSPATH . 'wp-includes/class-phpass.php';
            $wp_hasher = new PasswordHash( 8, true );
        }

        $key = wp_generate_password( 20, false );

        /**
         * Filters the user activation key.
         *
         * @since 3.5.0
         *
         * @param string $key     The activation key.
         * @param int    $user_id The user ID.
         */
        $key = apply_filters( 'user_activation_key', $key, $user_id );

        // Now insert the key, so that it can be verified against.
        $wpdb->update( $wpdb->users, array( 'user_activation_key' => $key ), array( 'user_login' => $user_login ) );

        $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
    }

这段代码做了这些事情:

  • 判断 $notify 是否为 'user' 或者 'both',只有在这种情况下才生成激活密钥。
  • 如果 $wp_hasher 对象不存在,则加载 class-phpass.php 文件,并创建 $wp_hasher 对象,用于密码哈希。
  • 使用 wp_generate_password() 函数生成一个 20 位的随机密码作为激活密钥。
  • 应用 user_activation_key 过滤器,允许开发者修改激活密钥。
  • 将激活密钥更新到数据库的 wp_users 表中。
  • 获取博客名称 $blogname,用于邮件内容。

4. 构建邮件内容

接下来,函数会根据 $notify 的值,分别构建管理员和用户的邮件内容。

4.1 管理员邮件

    if ( 'admin' === $notify || 'both' === $notify ) {
        $message = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "rnrn";
        $message .= sprintf( __( 'Username: %s' ), $user_login ) . "rn";
        $message .= sprintf( __( 'E-mail: %s' ), $user_email ) . "rn";

        /**
         * Fires after the new user notification email is sent to the site admin.
         *
         * @since 5.2.0
         *
         * @param WP_User $user   User object.
         * @param string  $blogname The site title.
         */
        do_action( 'wp_new_user_notification_email_admin', $user, $blogname );

        @wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] New User Registration' ), $blogname ), $message );
    }

这段代码:

  • 构建了管理员邮件的内容,包括网站名称、用户名和邮箱。
  • 触发 wp_new_user_notification_email_admin 动作钩子,允许开发者在管理员邮件发送之前进行自定义。
  • 使用 wp_mail() 函数发送邮件给管理员,邮件主题是 [网站名称] New User Registration

4.2 用户邮件

    if ( 'user' === $notify || ( 'both' === $notify && empty( $deprecated ) ) ) {
        // The `$deprecated` argument is kept to avoid breaking any plugins that may be passing
        // a third argument to the function's usage.

        $message = sprintf( __( 'Welcome to %s!' ), wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) ) . "rnrn";

        if ( get_option( 'users_require_email' ) ) {
            $message .= sprintf( __( 'To activate your account, please click the following link:' ) . "rnrn" );
            $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . ">rnrn";
            $message .= sprintf( __( 'If you have any problems, please contact us at %s.' ), get_option( 'admin_email' ) ) . "rnrn";
        } else {
            $message .= sprintf( __( 'Your username is: %s' ), $user_login ) . "rnrn";
            $message .= sprintf( __( 'To set your password, visit the following address:' ) . "rnrn" );
            $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . ">rnrn";
            $message .= sprintf( __( 'If you have any problems, please contact us at %s.' ), get_option( 'admin_email' ) ) . "rnrn";
        }

        /**
         * Fires after the new user notification email is sent to the new user.
         *
         * @since 5.2.0
         *
         * @param WP_User $user      User object.
         * @param string  $blogname The site title.
         */
        do_action( 'wp_new_user_notification_email', $user, $blogname );

        wp_mail( $user_email, sprintf( __( '[%s] Your username and password info' ), $blogname ), $message );
    }

这段代码有点长,我们来分解一下:

  • 首先判断 $notify 是否为 'user' 或者 'both',并且 $deprecated 是否为空。这个 $deprecated 参数是为了兼容旧版本的插件,可以忽略。
  • 构建用户邮件的内容,首先是欢迎信息。
  • 然后判断是否启用了用户邮箱验证 (get_option( 'users_require_email' )):
    • 如果启用了邮箱验证,则生成激活链接,让用户点击激活账号。
    • 如果没有启用邮箱验证,则显示用户名,并生成重置密码的链接。
  • 触发 wp_new_user_notification_email 动作钩子,允许开发者在用户邮件发送之前进行自定义。
  • 使用 wp_mail() 函数发送邮件给用户,邮件主题是 [网站名称] Your username and password info

5. wp_mail() 函数

在上面,我们多次提到了 wp_mail() 函数,这个函数是WordPress的核心邮件发送函数,它封装了PHP的 mail() 函数,并提供了一些额外的功能,比如支持SMTP服务器。

wp_mail() 函数的定义如下:

/**
 * Sends an email, similar to PHP's mail function.
 *
 * A true return value does not automatically mean that the user received the
 * email successfully. It just means that the method that WordPress uses was able
 * to process the request without any errors.
 *
 * The default content type of the email is `text/plain`. For HTML email, set the
 * `$headers` parameter accordingly.
 *
 * @since 1.2.1
 *
 * @param string|string[] $to          Array or comma-separated list of email addresses to send message.
 * @param string          $subject     Email subject.
 * @param string          $message     Message contents.
 * @param string|string[] $headers     Optional. Additional headers. Use an array to send multiple headers.
 *                                     Default empty string.
 * @param string|string[] $attachments Optional. Path to file(s) to attach. Use an array to send multiple attachments.
 *                                     Default empty array.
 * @return bool Whether the email contents were sent successfully.
 */
function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
    //... 函数体
}

简单来说,wp_mail() 函数接收以下参数:

  • $to:收件人邮箱地址,可以是字符串或者数组。
  • $subject:邮件主题。
  • $message:邮件内容。
  • $headers:邮件头部信息,比如 Content-TypeCc 等,可以是字符串或者数组。
  • $attachments:附件,可以是字符串或者数组。

wp_mail() 函数内部会根据你的WordPress配置,选择合适的邮件发送方式,比如使用PHP的 mail() 函数,或者使用SMTP服务器。

6. 钩子 (Hooks)

wp_new_user_notification() 函数中,我们看到了两个动作钩子:

  • wp_new_user_notification_email_admin:在管理员邮件发送之前触发。
  • wp_new_user_notification_email:在用户邮件发送之前触发。

这些钩子允许开发者修改邮件的内容、主题、头部信息等,提供了非常强大的自定义能力。

例如,你可以使用以下代码修改管理员邮件的主题:

add_action( 'wp_new_user_notification_email_admin', 'my_custom_admin_email', 10, 2 );

function my_custom_admin_email( $user, $blogname ) {
    add_filter( 'wp_mail_subject', 'my_custom_admin_email_subject', 10, 1 );
}

function my_custom_admin_email_subject( $subject ) {
    return '[重要] 有新人注册啦!';
}

这段代码首先使用 add_action() 函数注册 wp_new_user_notification_email_admin 动作钩子,然后在 my_custom_admin_email() 函数中使用 add_filter() 函数注册 wp_mail_subject 过滤器,修改邮件主题。

7. 总结

好了,各位观众老爷们,今天的“WordPress源码解剖”讲座就到这里了。我们一起深入剖析了 wp_new_user_notification() 函数的源码,了解了它的工作原理,以及如何通过钩子进行自定义。

为了方便大家理解,我把关键步骤总结成一个表格:

步骤 说明 涉及函数/变量
1. 参数处理 处理 $user_id$notify 参数,获取用户数据。 get_userdata(), stripslashes()
2. 生成密钥 如果需要激活账号,则生成激活密钥,并更新到数据库。 wp_generate_password(), apply_filters( 'user_activation_key' ), $wpdb->update()
3. 构建邮件 根据 $notify 的值,分别构建管理员和用户的邮件内容。 sprintf(), __( )
4. 发送邮件 使用 wp_mail() 函数发送邮件。 wp_mail(), do_action( 'wp_new_user_notification_email_admin' ), do_action( 'wp_new_user_notification_email' )

希望今天的讲座能对大家有所帮助。记住,源码是最好的老师,多看源码,才能真正理解WordPress的精髓。下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注