搜索全站
数据库 17 分钟阅读

WordPress REST API 入门:调用方式、鉴权与自定义端点

REST API 是自动化发布、前后端分离和小程序对接的基础。本文讲清 wp-json 的默认端点、三种鉴权方式(Cookie nonce / 应用密码 / JWT)的适用场景、register_rest_route 自定义接口写法,以及 401/403 排查思路。

U
UFO_PF 2017-07-31 · 阅读 17 分钟
Wo 数据库
阅读提示
本文约 6,742 字,预计阅读 17 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:为什么现在必须懂 REST API

早期插件要拿数据只能在 PHP 里写 WP_Query。现在这些场景全走 REST API:

  • 用 Python/Node 脚本批量发布文章(本项目阶段 3 就要用);
  • 小程序、App 拉取站点内容;
  • 前后端分离(Next.js / Nuxt 做前台,WordPress 只做后端);
  • 区块编辑器本身——Gutenberg 完全依赖 REST API 读写数据。

反过来它也是攻击面:未授权的用户枚举、内容抓取。所以既要会用,也要知道怎么收口。

原理分析:wp-json 的结构与默认端点

所有 REST 请求走同一个前缀:

https://example.com/wp-json/

根路径返回 API 索引(所有已注册的命名空间和路由):

curl -s https://example.com/wp-json/ | python -m json.tool | head -40

核心命名空间是 wp/v2:

端点 说明
/wp-json/wp/v2/posts 文章列表,支持 ?per_page=&page=&search=&categories=
/wp-json/wp/v2/posts/<id> 单篇文章
/wp-json/wp/v2/pages 页面
/wp-json/wp/v2/categories / tags 分类 / 标签
/wp-json/wp/v2/media 媒体库
/wp-json/wp/v2/users 用户(需鉴权)
/wp-json/wp/v2/settings 站点设置(需鉴权)

只读请求默认不需要鉴权(公开内容本来就能访问)。写操作(POST/PUT/DELETE)必须鉴权。

批量拉取时看分页响应头:

curl -I "https://example.com/wp-json/wp/v2/posts?per_page=100"
# X-WP-Total: 109
# X-WP-TotalPages: 2

保姆级实操

一、只读调用(无需鉴权)

# 最新 10 篇
curl -s "https://example.com/wp-json/wp/v2/posts?per_page=10"

# 只要标题和链接
curl -s "https://example.com/wp-json/wp/v2/posts?_fields=id,title,link&per_page=100"

# 搜索
curl -s "https://example.com/wp-json/wp/v2/posts?search=缓存"

# 按分类 / 日期 / 排序
curl -s "https://example.com/wp-json/wp/v2/posts?categories=5"
curl -s "https://example.com/wp-json/wp/v2/posts?after=2026-01-01T00:00:00&before=2026-10-01T00:00:00"
curl -s "https://example.com/wp-json/wp/v2/posts?orderby=title&order=asc"

二、鉴权方式一:应用密码(推荐)

WordPress 5.6+ 内置。生成:后台 用户 → 个人资料 → 应用密码 → 输入名称 → 生成,得到 xxxx xxxx xxxx xxxx xxxx xxxx。

curl -X POST "https://example.com/wp-json/wp/v2/posts" \
  -u "UFO_PF:xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "测试文章",
    "content": "正文内容",
    "status": "draft",
    "categories": [5],
    "tags": [12, 13]
  }'

Python 写法:

import requests, base64

BASE   = "https://example.com/wp-json/wp/v2"
USER   = "UFO_PF"
APP_PW = "xxxxxxxxxxxxxxxxxxxxxxxx"

token = base64.b64encode(f"{USER}:{APP_PW}".encode()).decode()
headers = {
    "Authorization": f"Basic {token}",
    "Content-Type": "application/json",
}

r = requests.post(f"{BASE}/posts", headers=headers, json={
    "title": "REST API 发布的文章",
    "content": "<p>正文</p>",
    "status": "publish",
    "excerpt": "摘要",
})
print(r.status_code, r.json().get("link"))

注意:应用密码要求站点必须启用 HTTPS,否则 WordPress 会拒绝。生产环境请务必上 HTTPS。

三、鉴权方式二:Cookie + nonce(浏览器内、主题插件里)

wp_localize_script( 'my-script', 'wpApiSettings', array(
    'root'  => esc_url_raw( rest_url() ),
    'nonce' => wp_create_nonce( 'wp_rest' ),
) );
fetch(`${wpApiSettings.root}wp/v2/posts`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-WP-Nonce': wpApiSettings.nonce,
    },
    body: JSON.stringify({ title: '新文章', status: 'draft' }),
})
.then(r => r.json())
.then(d => console.log(d));

四、鉴权方式三:JWT(前后端分离、App)

装插件 “JWT Authentication for WP REST API”:

// wp-config.php
define( 'JWT_AUTH_SECRET_KEY', '你的随机长字符串' );
define( 'JWT_AUTH_CORS_ENABLE', true );

Nginx 需要放行 Authorization 头:

fastcgi_param HTTP_AUTHORIZATION $http_authorization;

获取 token:

curl -X POST "https://example.com/wp-json/jwt-auth/v1/token" \
  -H "Content-Type: application/json" \
  -d '{"username":"UFO_PF","password":"真实登录密码"}'

之后带 Authorization: Bearer <token> 请求。

五、自定义端点(register_rest_route)

add_action( 'rest_api_init', function() {

    register_rest_route( 'mmf/v1', '/stats', array(
        'methods'             => 'GET',
        'callback'            => 'mmf_api_stats',
        'permission_callback' => '__return_true',
    ) );

    register_rest_route( 'mmf/v1', '/post-count', array(
        'methods'  => 'GET',
        'callback' => 'mmf_api_post_count',
        'permission_callback' => function() {
            return current_user_can( 'edit_posts' );
        },
        'args' => array(
            'type' => array(
                'default'           => 'post',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => function( $param ) {
                    return in_array( $param, array( 'post', 'page' ), true );
                },
            ),
        ),
    ) );
});

function mmf_api_stats( $request ) {
    return new WP_REST_Response( array(
        'posts'    => (int) wp_count_posts( 'post' )->publish,
        'comments' => (int) wp_count_comments()->approved,
        'time'     => current_time( 'mysql' ),
    ), 200 );
}

function mmf_api_post_count( $request ) {
    $type = $request->get_param( 'type' );
    $c    = wp_count_posts( $type );
    return rest_ensure_response( array( 'type' => $type, 'publish' => (int) $c->publish ) );
}

permission_callback 在 WordPress 5.5+ 是必填的,不写会在站点健康里报”REST API 端点缺少权限回调”。

六、安全收口

关闭用户端点(防用户名枚举):

add_filter( 'rest_endpoints', function( $endpoints ) {
    if ( isset( $endpoints['/wp/v2/users'] ) ) {
        unset( $endpoints['/wp/v2/users'] );
    }
    return $endpoints;
});

限制匿名写操作:

add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! empty( $result ) ) {
        return $result;
    }
    if ( ! is_user_logged_in() && in_array( $_SERVER['REQUEST_METHOD'], array( 'POST', 'PUT', 'DELETE' ), true ) ) {
        return new WP_Error( 'rest_not_logged_in', '请先登录', array( 'status' => 401 ) );
    }
    return $result;
});

不要一刀切关闭 REST API,否则区块编辑器、站点编辑器和很多插件会失效。只关闭不需要的端点。

常见踩坑与失败案例

  1. 401 rest_cannot_create:应用密码权限不够,或该用户角色没有 publish_posts 能力。检查 wp cap list <role>。
  2. 案例一:curl 用应用密码一直 401,最后发现站点在 Cloudflare 后面开了”机器人攻击防护”,拦截了带 Basic Auth 的自动化请求。在 WAF 里放行 /wp-json/wp/v2/posts 的 POST。
  3. 403 rest_forbidden:安全插件(Wordfence)拦了,去插件日志看。
  4. 案例二:Nginx 反代没传 Authorization 头,JWT 一直拿不到 token。加 fastcgi_param HTTP_AUTHORIZATION $http_authorization;。
  5. 参数校验失败:args 里 required => true 但没传,会返回 rest_missing_callback_param。
  6. HTTPS 要求:应用密码在 HTTP 站点上被禁用。开发环境可临时加:

php
add_filter( 'wp_is_application_passwords_available', '__return_true' );

  1. 返回 404:固定链接是朴素模式时 REST 路由不工作。去 设置 → 固定链接 选一个非朴素结构。
  2. 性能:per_page 最大 100,批量拉取要分页;用 _fields 裁剪响应能显著减小体积。

总结

REST API 三个必知点:只读默认公开、写操作必须鉴权、生产环境首选”应用密码 + HTTPS + Basic Auth”(比 JWT 简单、比 Cookie nonce 更适合脚本)。自定义端点用 register_rest_route,permission_callback 是必填项。安全上只做减法——关掉 /wp/v2/users 防用户枚举,必要时限制匿名写,绝不整体关闭 REST API。批量脚本用 X-WP-Total 头读总数做分页,用 _fields 裁剪响应。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。