剖析 WordPress `wp_ajax_send_comment()` 函数的源码:如何处理评论提交的 AJAX 请求。

大家好,我是老码,今天咱们来聊聊 WordPress 评论这事儿,特别是那个藏在幕后的英雄——wp_ajax_send_comment()。 准备好了吗?咱们开讲!

一、 评论,WordPress的心脏跳动

评论,对于一个博客或者网站来说,简直就是心脏跳动。没有评论,就像一场独角戏,冷冷清清,毫无生气。 WordPress 当然深知这一点,所以它的评论系统相当完善,但也因此代码量也比较可观。

今天,我们聚焦在评论提交的 AJAX 请求处理上。 AJAX 意味着异步,这意味着用户提交评论后,无需刷新页面,就能看到评论提交的结果,大大提升了用户体验。而 wp_ajax_send_comment() 就是负责处理这个异步请求的关键函数。

二、 wp_ajax_send_comment() 在哪?

这个函数定义在 wp-includes/comment.php 文件里。 找到它,你就能发现宝藏。

三、 wp_ajax_send_comment() 的真面目

wp_ajax_send_comment() 并没有直接定义,而是通过 action hook 注册的。

add_action( 'wp_ajax_nopriv_wp_comment_post', 'wp_ajax_send_comment' ); // 未登录用户
add_action( 'wp_ajax_wp_comment_post', 'wp_ajax_send_comment' ); // 登录用户

这意味着,当用户提交评论时,WordPress 会触发 wp_comment_post 这个 action,然后 wp_ajax_send_comment 函数就会被调用。 注意区分 wp_comment_post 这个 action 和 wp_ajax_post 这个action。 wp_ajax_post是处理普通 post 请求的,和评论没关系。

四、 源码剖析,一层层扒开它的外衣

好了,重头戏来了,咱们一步步剖析 wp_ajax_send_comment() 的源码。

function wp_ajax_send_comment() {
    global $wp_query, $comment;

    // Check nonce security.
    check_ajax_referer( 'wp_comment_nonce', '_wpnonce' );

    $comment = wp_handle_comment_submission( wp_unslash( $_POST ) );
    if ( is_wp_error( $comment ) ) {
        $data = array(
            'error'   => $comment->get_error_message(),
            'success' => false,
        );

        wp_send_json( $data );
    }

    $user = wp_get_current_user();
    do_action( 'set_comment_cookies', $comment, $user );

    $GLOBALS['comment'] = $comment; // WPCS: override ok.
    get_template_part( 'template-parts/comment', 'item' );

    wp_die();
}

是不是很简单? 别急,咱们来细细分析:

  1. 全局变量:

    • global $wp_query, $comment; 声明了全局变量 $wp_query$comment$comment 之后会被赋值为新提交的评论对象。
  2. 安全检查:

    • check_ajax_referer( 'wp_comment_nonce', '_wpnonce' ); 这个是安全卫士,检查 nonce 值,防止 CSRF 攻击。 wp_comment_nonce 是 action 的名称,_wpnonce 是前端传递 nonce 值的字段名。 如果 nonce 值不匹配,请求会被拒绝。 如何生成这个 nonce 值呢? 一般在评论表单中添加: wp_nonce_field( 'wp_comment_nonce', '_wpnonce' );
  3. 处理评论提交:

    • $comment = wp_handle_comment_submission( wp_unslash( $_POST ) ); 这是核心部分,调用 wp_handle_comment_submission 函数来处理评论提交。 这个函数会进行各种验证、过滤、保存等操作。 wp_unslash( $_POST ) 的作用是移除 $_POST 数组中每个元素的反斜杠(如果存在)。 这是为了处理 magic quotes 的遗留问题。
  4. 错误处理:

    • if ( is_wp_error( $comment ) ) { ... } 如果 wp_handle_comment_submission 函数返回一个 WP_Error 对象,说明评论提交失败。 此时,会构建一个包含错误信息的 JSON 对象,并发送给客户端。
  5. 设置 Cookie:

    • $user = wp_get_current_user(); 获取当前用户对象。
    • do_action( 'set_comment_cookies', $comment, $user ); 触发 set_comment_cookies action,用于设置评论相关的 Cookie (例如,评论者的姓名、邮箱等)。
  6. 渲染评论:

    • $GLOBALS['comment'] = $comment;$comment 赋值给全局变量 $GLOBALS['comment']。 这是为了让模板文件能够访问到评论数据。
    • get_template_part( 'template-parts/comment', 'item' ); 加载 template-parts/comment-item.php 模板文件,用于渲染新提交的评论。 这个模板文件负责将评论数据转换为 HTML 代码。 默认主题一般会有这个文件,如果没有,可以自行创建。
  7. 结束请求:

    • wp_die(); 结束 AJAX 请求。 这个函数会输出 0 并退出 PHP 脚本。

五、 wp_handle_comment_submission():评论处理的大管家

刚才我们提到, wp_handle_comment_submission() 是处理评论提交的核心函数。 这个函数的功能非常强大,我们来简单了解一下。

wp_handle_comment_submission() 主要做了以下事情:

  • 获取评论数据:$_POST 数组中获取评论数据,包括作者、邮箱、网址、评论内容等。
  • 验证评论数据: 验证评论数据是否合法,例如,评论内容是否为空,邮箱格式是否正确等。
  • 检查是否重复评论: 检查是否已经存在相同的评论。
  • 检查是否被列入黑名单: 检查评论者 IP 地址、邮箱、网址等是否被列入黑名单。
  • 检查是否需要审核: 根据 WordPress 的设置,判断评论是否需要人工审核。
  • 保存评论: 将评论数据保存到数据库中。
  • 发送通知邮件: 如果有新的评论需要审核,会发送通知邮件给管理员。

可以看出, wp_handle_comment_submission() 承担了评论处理的绝大部分工作。

六、 前端如何配合?

光有后端代码是不够的,前端也需要配合才能完成 AJAX 评论提交。 前端的主要任务是:

  1. 收集评论数据: 从评论表单中收集评论数据,例如,作者、邮箱、网址、评论内容等。
  2. 生成 nonce 值: 通过 WordPress 提供的函数生成 nonce 值,并将其添加到评论表单中。
  3. 发送 AJAX 请求: 使用 JavaScript 发送 AJAX 请求到 wp-admin/admin-ajax.php
  4. 处理响应: 根据 AJAX 请求的响应,显示评论提交的结果。

下面是一个简单的 JavaScript 代码示例:

jQuery(document).ready(function($) {
    $('#commentform').submit(function(e) {
        e.preventDefault(); // 阻止默认的表单提交

        var data = $(this).serialize(); // 序列化表单数据
        data += '&action=wp_comment_post'; // 添加 action 参数

        $.ajax({
            url: wp.ajax.settings.url, // WordPress AJAX URL
            type: 'POST',
            data: data,
            dataType: 'json',
            success: function(response) {
                if (response.success === false) {
                    // 显示错误信息
                    alert(response.error);
                } else {
                    // 显示评论
                    $('#comments').append(response); //这里要根据实际返回的评论HTML结构进行调整
                    $('#commentform')[0].reset(); // 清空表单
                }
            },
            error: function(xhr, status, error) {
                console.error('AJAX 请求失败: ' + error);
            }
        });
    });
});

注意:

  • wp.ajax.settings.url 是 WordPress 提供的 AJAX URL,可以在前端通过 wp_localize_script 函数传递。
  • action=wp_comment_post 是告诉 WordPress 我们要执行 wp_ajax_send_comment 函数。
  • dataType: 'json' 指定服务器返回的数据类型为 JSON。
  • 成功提交之后如何显示评论,需要根据你的主题模板进行调整。 默认情况下, get_template_part( 'template-parts/comment', 'item' ); 会加载评论模板,然后你需要将这个模板返回的 HTML 代码插入到评论列表中。

七、 一些需要注意的点

  • 评论审核: 如果评论需要审核, wp_ajax_send_comment() 不会立即显示评论,而是会显示一条提示信息,告诉用户评论正在等待审核。
  • 缓存: 如果你的网站使用了缓存,需要注意清除评论相关的缓存,否则新提交的评论可能不会立即显示。
  • 主题兼容性: 不同的主题可能对评论的显示方式有不同的处理,因此你需要根据你的主题进行相应的调整。
  • 插件冲突: 某些插件可能会修改评论的处理流程,导致 wp_ajax_send_comment() 无法正常工作。 如果遇到问题,可以尝试禁用插件来排除冲突。
  • 垃圾评论: 垃圾评论是 WordPress 的一大难题。 可以使用 Akismet 等插件来过滤垃圾评论。

八、 实战演练:自定义评论 AJAX 处理

有时候,你可能需要自定义评论 AJAX 处理的流程。 例如,你可能需要在评论提交后发送自定义的通知邮件,或者需要在评论保存到数据库之前进行一些额外的处理。

要实现自定义的评论 AJAX 处理,你可以使用 wp_ajax_wp_comment_postwp_ajax_nopriv_wp_comment_post 这两个 action hook。

下面是一个简单的示例:

function my_custom_comment_ajax_handler() {
    // 1. 安全检查
    check_ajax_referer( 'wp_comment_nonce', '_wpnonce' );

    // 2. 处理评论提交 (可以修改 $_POST 数据)
    $comment = wp_handle_comment_submission( wp_unslash( $_POST ) );

    if ( is_wp_error( $comment ) ) {
        $data = array(
            'error'   => $comment->get_error_message(),
            'success' => false,
        );
        wp_send_json( $data );
    }

    // 3.  自定义操作
    // 例如,发送自定义的通知邮件
    $comment_id = $comment->comment_ID;
    $comment_author_email = $comment->comment_author_email;
    $comment_content = $comment->comment_content;

    // 这里添加发送邮件的代码
    // 例如: wp_mail( '[email protected]', 'New Comment', 'Author: ' . $comment_author_email . "n" . 'Content: ' . $comment_content );

    // 4. 设置 Cookie
    $user = wp_get_current_user();
    do_action( 'set_comment_cookies', $comment, $user );

    // 5. 渲染评论
    $GLOBALS['comment'] = $comment; // WPCS: override ok.
    ob_start();
    get_template_part( 'template-parts/comment', 'item' );
    $comment_html = ob_get_clean();

    $data = array(
        'success' => true,
        'html' => $comment_html,
    );
    wp_send_json( $data );

    // 6. 结束请求
    wp_die();
}

remove_action( 'wp_ajax_nopriv_wp_comment_post', 'wp_ajax_send_comment' );
remove_action( 'wp_ajax_wp_comment_post', 'wp_ajax_send_comment' );
add_action( 'wp_ajax_nopriv_wp_comment_post', 'my_custom_comment_ajax_handler' );
add_action( 'wp_ajax_wp_comment_post', 'my_custom_comment_ajax_handler' );

在这个示例中,我们首先移除了默认的 wp_ajax_send_comment 函数,然后添加了自己的 my_custom_comment_ajax_handler 函数。 在 my_custom_comment_ajax_handler 函数中,我们可以执行任何自定义的操作。需要注意的是,我们要自己渲染评论,并且将渲染的HTML代码通过json返回给前端。

九、 总结

wp_ajax_send_comment() 是 WordPress 评论 AJAX 处理的核心函数。 通过深入了解它的源码,我们可以更好地理解 WordPress 评论系统的运作机制,并可以根据自己的需求进行自定义。

希望今天的讲座对你有所帮助。 记住,编程的世界充满了乐趣,只要你肯学习,就能掌握它。 下次再见!

发表回复

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