插件冲突导致 REST API 500?教你用 Code Snippets 精准摘掉捣乱的钩子(附代码)

上一篇文章《WordPress 一直报”密码不正确”?不一定是密码错了》讲到:某个插件接管了 REST 认证,把应用程序密码当登录密码校验,导致所有带认证头的 API 请求全部 500。

停用插件当然能解决,但如果你需要这个插件的其他功能(比如本文案例里的小程序),就需要更精细的手术:只摘掉它捣乱的那部分,其余照常。整个过程用 Code Snippets 插件完成,不改任何插件文件、不受插件升级影响、随时可撤销。

一、准备工具:Code Snippets 插件

后台 → 插件 → 安装 Code Snippets(免费版够用)。它让你把自定义 PHP 代码片段加进网站,而不用改主题的 functions.php——改主题文件会在升级时被覆盖,Code Snippets 不会。

装好后在后台左侧菜单会有「Snippets(片段)」入口,点 Add New 新建片段,粘贴代码,勾选启用即可。

二、第一步:诊断——让网站自己列出认证钩子上挂了谁

不要靠猜。WordPress 的认证链路是两条钩子:

  • rest_authentication_errors:认证出错时的处理
  • determine_current_user:确定当前用户是谁

任何在这两条钩子上”加戏”的插件,都可能污染认证结果。下面这段诊断代码会把两条钩子上挂的所有回调函数名和源文件路径输出出来:

// 临时诊断:列出 REST 认证钩子上的所有回调(用完删除!)
add_action( 'rest_api_init', function () {
    register_rest_route( 'diag/v1', '/hooks', array(
        'methods'             => 'GET',
        'permission_callback' => '__return_true',
        'callback'            => function () {
            global $wp_filter;
            $out = array();
            foreach ( array( 'rest_authentication_errors', 'determine_current_user' ) as $hook ) {
                $out[ $hook ] = array();
                if ( empty( $wp_filter[ $hook ] ) ) { continue; }
                foreach ( $wp_filter[ $hook ]->callbacks as $prio => $cbs ) {
                    foreach ( $cbs as $cb ) {
                        $f    = $cb['function'];
                        $info = array( 'priority' => $prio );
                        try {
                            if ( $f instanceof Closure ) {
                                $r = new ReflectionFunction( $f );
                                $info['closure'] = $r->getFileName() . ':' . $r->getStartLine();
                            } elseif ( is_string( $f ) ) {
                                $info['function'] = $f;
                                if ( function_exists( $f ) ) {
                                    $r = new ReflectionFunction( $f );
                                    $info['file'] = $r->getFileName() . ':' . $r->getStartLine();
                                }
                            } elseif ( is_array( $f ) && isset( $f[1] ) ) {
                                $cls = is_object( $f[0] ) ? get_class( $f[0] ) : (string) $f[0];
                                $info['method'] = $cls . '::' . $f[1];
                                if ( class_exists( $cls ) && method_exists( $cls, $f[1] ) ) {
                                    $r = new ReflectionMethod( $cls, $f[1] );
                                    $info['file'] = $r->getFileName() . ':' . $r->getStartLine();
                                }
                            }
                        } catch ( \Throwable $e ) {
                            $info['error'] = $e->getMessage();
                        }
                        $out[ $hook ][] = $info;
                    }
                }
            }
            return $out;
        },
    ) );
} );

保存启用后,浏览器访问:

https://你的域名/wp-json/diag/v1/hooks

你会看到类似这样的输出:

{
  "rest_authentication_errors": [
    { "priority": 10, "function": "WWA_basic_auth_error", "file": ".../plugins/某插件/includes/functions.php:1097" }
  ],
  "determine_current_user": [
    { "priority": 2,  "function": "wp_rest_application_password_lookup..." },
    { "priority": 20, "function": "WWA_basic_auth_handler", "file": ".../plugins/某插件/includes/functions.php:1047" }
  ]
}

怎么读这个结果:

  • wp_rest_application_password_* 这些是 WordPress 核心的认证函数,别碰
  • 文件路径里带 plugins/某插件名/ 的,就是插件挂上来的——找到那个和你的症状对应的插件
  • 记下它的函数名和优先级(priority),下一步要用

⚠️ 这个诊断接口是公开的,会暴露服务器文件路径,排查完务必删除或停用这个片段。

三、第二步:修复——remove_filter 精准摘除

拿到函数名和优先级后,修复就是两行 remove_filter。以某小程序插件为例:

// 修复:某插件的 Basic 认证接管与应用程序密码冲突
// 只摘除它的两个 REST 认证回调,插件其余功能不受影响
add_action( 'rest_api_init', function () {
    remove_filter( 'rest_authentication_errors', 'WWA_basic_auth_error', 10 );
    remove_filter( 'determine_current_user', 'WWA_basic_auth_handler', 20 );
}, 0 );

使用说明(照抄上面的模板,替换成你自己诊断出的值):

  • 第一行:钩子名 rest_authentication_errors + 函数名 + 优先级
  • 第二行:钩子名 determine_current_user + 函数名 + 优先级
  • 外层的 add_action(..., 0) 表示在 REST 处理开始前执行摘除动作,优先级必须是 0 或很小的数字

新建一个片段粘贴进去,启用。然后验证:

curl -u '你的用户名:你的应用程序密码' https://你的域名/wp-json/wp/v2/users/me
  • 返回 200 + 用户信息 → 修复成功
  • 还是 500 → 说明还有别的回调捣乱,回到诊断接口看看是不是漏摘了,或函数挂的钩子不同(少数插件挂 rest_pre_dispatch 等其他钩子)

四、为什么这样写而不是改插件文件

方案 升级插件后 风险
直接改插件源码 修改丢失,问题复发 可能改出别的问题
停用插件 问题解决 需要的功能没了
Code Snippets 摘钩子 继续生效(除非新版改了函数名) 随时停用片段即可回滚

唯一要注意的是:如果插件某次大版本更新改了函数名或优先级,这个片段会失效(问题复发),重新跑一遍诊断、更新片段里的函数名即可。

五、别忘了收尾

  1. 删除诊断片段(重要,它公开暴露文件路径)
  2. 去插件作者的渠道反馈这个 bug——「插件在 determine_current_user 上的回调会在应用程序密码验证成功后重复校验登录密码,导致 REST 500」,等官方修复的新版发布,就可以删掉这个修复片段了
  3. 测试插件自身功能是否正常(比如小程序端能否正常访问),万一受影响,停用片段即可回滚

六、思路总结

这套「诊断钩子 → 精准摘除 → 官方反馈」的组合拳,适用于所有「插件在某条 WordPress 链路上加了不该加的逻辑」类问题——不只是认证,菜单、评论、文章列表同理。核心就一句话:

先让系统告诉你”谁挂了什么”,再做外科手术,别猜、别乱改文件。

原创文章,作者:小微财服云,如若转载,请注明出处:https://www.779it.com/348.html

赞 (0)
小微财服云小微财服云
上一篇 1天前
下一篇 10小时前

相关推荐