PIX主题修复后台开启邮件回复通知前台游客评论严重超时的问题

经常访问本站的各位博友知道,近一年本站最大的一个问题就是当我后台开启邮件回复通知时,前台游客评论的时候,点击提交按钮,至少需要等待漫长的1分钟才会慢吞吞地显示提交成功,真是叔叔可忍婶婶不可忍。其实这个不是什么BUG,只能算是一个问题,因为我看好些网站开启后都会延迟,只不过这个主题延迟的有些离谱,以致于我找了好长世家没有找到原因,后台在沉沦兄弟、灵妹子Obaby的帮助下才确定是后台开启了这个功能。

刚开始我对这个功能不是很在意,但是后来一些经常互访的博友反馈收不到邮件和麻烦,因为不知道自己的评论是否得到我的回复。想了又想,终于决定这次要把这个问题彻底解决。

这次只涉及一个文件pix/inc/pix-mail.php,之所以发生堵塞延迟,是因为我的邮件通知功能是通过 wp_insert_comment钩子直接触发的,而邮件发送(尤其是SMTP连接)是同步操作,会阻塞AJAX请求直到邮件发送完成。当SMTP服务器响应慢或连接超时时,会导致整个评论提交过程卡住。

这次修改是采用 ​​Redis队列 + Swoole协程并发​​ 方案,显著提升邮件发送性能。

以我的Debian系统为例,因为我的网站一直使用Redis,所以只需要安装swoole:

sudo apt update
sudo apt install -y build-essential php-dev libssl-dev  //安装依赖
sudo pecl install swoole

需要说明的是,这个不是安装PHP里面的那个Swoole扩展,我的PHP版本是8.4,里面是Swoole6。安装Swoole,会问你是否支持好几个功能,我只选择支持前两个ssl和http2,选择更多我这里安装失败。最后将extension=swoole.so手工加入到php.ini里,重启php即可。

做完以上,就可以将以下代码完整替换pix/inc/pix-mail.php的内容,建议先备份。

<?php
/*-----------------------------------------------------------------------------------*/
/* 高性能邮件队列系统(Redis + 兼容模式) */
/*-----------------------------------------------------------------------------------*/
if (!class_exists('WP_Ultimate_Mail_Queue')) {
    class WP_Ultimate_Mail_Queue {
        private $redis;
        private $queue_name = 'wp_mail_queue_v2';
        private $concurrency = 20;
        private $smtp_connections = [];

        public function __construct() {
            // 初始化Redis连接
            $this->redis = new Redis();
            $this->redis->connect('127.0.0.1', 6379, 1.5);
            
            // 兼容模式:通过WordPress钩子触发处理(避免Swoole CLI限制)
            add_action('shutdown', [$this, 'process_queue']);
        }

        // 加入队列
        public function add_task($to, $subject, $message, $headers = '') {
            $task = [
                'to'      => $to,
                'subject' => $subject,
                'message' => $message,
                'headers' => $headers,
                'attempt' => 0,
                'created' => time()
            ];
            $this->redis->lPush($this->queue_name, json_encode($task));
        }

        // 处理队列(兼容模式)
        public function process_queue() {
            $pending = $this->redis->lLen($this->queue_name);
            if ($pending === 0) return;

            // 批量获取任务(非阻塞)
            $tasks = [];
            for ($i = 0; $i < min($this->concurrency, $pending); $i++) {
                $task = $this->redis->rPop($this->queue_name);
                if ($task) $tasks[] = json_decode($task, true);
            }

            // 同步发送(兼容环境)
            foreach ($tasks as $task) {
                $result = $this->send_mail($task);
                if (!$result && $task['attempt'] < 3) {
                    $task['attempt']++;
                    $this->redis->lPush($this->queue_name, json_encode($task));
                }
            }
        }

        // 邮件发送核心方法(修复数组访问警告)
        private function send_mail($task) {
            if (!is_array($task) || empty($task['to'])) {
                error_log('Invalid mail task format');
                return false;
            }

            try {
                // 动态加载PHPMailer
                if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
                    require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
                    require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
                    require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
                }

                $mail = new PHPMailer\PHPMailer\PHPMailer(true);
                if (get_op('site_smtp') == true) {
                    $mail->isSMTP();
                    $mail->Host       = get_op('smtp_server') ?: '';
                    $mail->Port       = get_op('smtp_port') ?: 465;
                    $mail->Username   = get_op('smtp_email') ?: '';
                    $mail->Password   = get_op('smtp_password') ?: '';
                    $mail->SMTPSecure = get_op('smtp_ssl') ?: 'ssl';
                    $mail->SMTPAuth   = true;
                    $mail->Timeout    = 3;
                }

                $mail->setFrom(get_op('smtp_email') ?: 'noreply@' . $_SERVER['SERVER_NAME'], get_op('smtp_name') ?: '');
                $mail->addAddress($task['to']);
                $mail->Subject = $task['subject'];
                $mail->msgHTML($task['message']);
                $mail->CharSet = get_option('blog_charset');
                $mail->send();
                return true;
            } catch (Exception $e) {
                error_log('Mail Error: ' . $e->getMessage());
                return false;
            }
        }
    }
}

// 初始化队列
global $wp_mail_queue;
$wp_mail_queue = new WP_Ultimate_Mail_Queue();

/*-----------------------------------------------------------------------------------*/
/* 邮件模板系统(完整实现) */
/*-----------------------------------------------------------------------------------*/
function ea_mail_template($content, $parent_id, $comment_id) {
    $blogname = get_bloginfo('name');
    $bloghome = get_bloginfo('url');
    $logo = get_op('mail_logo');
    $head_title = $logo ? '<img src="'.$logo.'" style="max-width:60px;">' : 
        '<h1 style="display:inline-block;font-size:16px;font-family:microsoft yahei;padding:12px 30px;background:#485dff;color:#fff;border-radius:3px;">'.$blogname.'</h1>';

    $comment = get_comment($comment_id);
    $post = get_post($comment->comment_post_ID);
    $parent_comment = get_comment($parent_id);

    $html = <<<HTML
<div class="email_warp" style="max-width:540px;width:100%;background:#fdfdff;margin:0 auto;padding:30px;border:1px solid #e0e8ff;border-radius:4px;">
    <div class="mail_head" style="text-align:center;margin-bottom:30px;">
        <a href="$bloghome" target="_blank">$head_title</a>
    </div>
    <p style="margin:0">Hi, {$parent_comment->comment_author}, 您曾在[$blogname]的评论:</p>
    <div class="mail_content" style="background:#ebebff;padding:20px;margin:10px 0 40px;">
        <p style="margin:0">{$parent_comment->comment_content}</p>
    </div>
    <p style="margin:0">{$comment->comment_author} 给您的回复:</p>
    <div class="mail_content" style="background:#ebebff;padding:20px;margin:10px 0 40px;">
        <p style="margin:0">$content</p>
    </div>
    <p>点击<a href="{$post->guid}" style="color:#3b37ca;text-decoration:none;">查看完整内容</a></p>
    <div class="mail_footer" style="text-align:center;margin-top:60px;">
        <p>Copyright © <a href="$bloghome" target="_blank" style="color:#3b37ca;text-decoration:none;">$blogname</a></p>
    </div>
</div>
HTML;
    return $html;
}

/*-----------------------------------------------------------------------------------*/
/* 邮件发送接口 */
/*-----------------------------------------------------------------------------------*/
function ea_basic_mail($from, $to, $subject, $content, $parent_id, $comment_id) {
    global $wp_mail_queue;
    $message = ea_mail_template($content, $parent_id, $comment_id);
    $headers = [
        'From: "' . get_bloginfo('name') . '" <' . $from . '>',
        'Content-Type: text/html; charset=' . get_option('blog_charset')
    ];
    $wp_mail_queue->add_task($to, $subject, $message, implode("\n", $headers));
}

/*-----------------------------------------------------------------------------------*/
/* 评论触发逻辑 */
/*-----------------------------------------------------------------------------------*/
if (get_op('comments_notify') == true) {
    add_action('wp_insert_comment', 'ea_global_send_mail', 10, 2);
}
function ea_global_send_mail($comment_id, $comment_approved) {
    if ($comment_approved != 1) return;
    $comment = get_comment($comment_id);
    $parent = $comment->comment_parent ? get_comment($comment->comment_parent) : null;
    if (!$parent || $parent->comment_author_email == $comment->comment_author_email) return;

    ea_basic_mail(
        $comment->comment_author_email,
        $parent->comment_author_email,
        '新评论回复![' . get_bloginfo('name') . ']',
        $comment->comment_content,
        $comment->comment_parent,
        $comment_id
    );
}
?>
PIX主题修复后台开启邮件回复通知前台游客评论严重超时的问题-似水流年

Comments | 10 条评论
  • 八对星星

    Microsoft Edge 138 Microsoft Edge 138 Windows 10 Windows 10 cn中国–四川–乐山 电信 ip address 171.213.*.*

    最近我也看到了Halo版本的PIX挺不错的,但是你这个是不是改过很多东西啊,好像很多都不一样了

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 cn中国 中国联通 ip address 2408:8220:5f10:16e0:*:*

      添加了好多功能,我感觉说是PRO版本也不为过了。😹

  • 龙笑天

    Firefox 142 Firefox 142 Windows 10 Windows 10 cn中国–广东–广州 联通 ip address 112.96.*.*

    可以的 评论提交速度拉满了💪

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 cn中国 中国联通 ip address 2408:8220:5f10:42b0:*:*

      比以前确实进步不少,但我觉得还有优化的空间,我个人能接受的是两秒,现在我感觉得四五秒。

  • 全局变量

    Google Chrome 132 Google Chrome 132 Windows 10 Windows 10 cn中国 中国联通 ip address 2408:8453:6a10:80ff:*:*

    我也是直接用的tp的插件,不过这个插件挺不错的分为同步和异步,异步就是提供了一个地址,访问这个地址才会发送所有未发送的邮件。

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 cn中国 中国联通 ip address 2408:8220:5f10:42b0:*:*

      我感觉你的挺快的。👍

  • obaby

    Google Chrome 134 Google Chrome 134 Mac OS X 10.15 Mac OS X 10.15 cn中国 中国联通 ip address 2408:8418:d10:3a69:*:*

    我是用的插件,简单粗暴。哈哈

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 cn中国 中国联通 ip address 2408:8220:5f10:42b0:*:*

      我这个装了插件也没啥用,以前的时间你是知道的。🤣

  • 网友小宋

    Microsoft Edge 131 Microsoft Edge 131 Android 10 Android 10 cn中国–河南 广电网 ip address 240a:42bc:c201:846:*:*

    wp邮件通知插件不是一大堆吗 我记得我爱水煮鱼有一个

    • 似水流年

      Microsoft Edge 109 Microsoft Edge 109 Windows 7 Windows 7 cn中国–河南–漯河 电信 ip address 222.89.*.*

      那个太臃肿了,好多插件我试过效果不明显,这次是这个主体本身有严重的问题。

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息