WordPress 建站指南 REST API 实战开发完整指南
WordPress 从 4.7 开始内置 REST API,你不需要装任何插件就能让 WordPress 和任何前端框架对话。我花了 3 周把一个 WordPress 站点改成 React 前端 + WordPress 后端分离架构,中间踩了 5 个坑才摸清楚这套东西怎么正确使用。
什么时候该用 REST API 而不是 WP-CLI
WP-CLI 适合服务器端批量操作(比如批量更新插件、数据库替换)。REST API 适合:
- 前后端分离站点(React/Vue)
- 移动端 App 后端
- 第三方系统集成
- 需要权限验证的远程操作
如果你的需求只是"命令行操作 WordPress",WP-CLI 已经够用,不需要绕道 REST API。
注册一个自定义端点
在 functions.php 或者独立插件里注册:
add_action('rest_api_init', function () {
register_rest_route('tech/v1', '/posts-stats', [
'methods' => 'GET',
'callback' => function ($request) {
$posts = wp_count_posts();
return [
'publish' => $posts->publish,
'draft' => $posts->draft,
'total' => $posts->total,
'last_updated' => get_lastpostmodified('GMT'),
];
},
'permission_callback' => '__return_true',
]);
});
这会创建一个端点:/wp-json/tech/v1/posts-stats
**验证方式**:GET https://yoursite.com/wp-json/tech/v1/posts-stats
带参数的端点
register_rest_route('tech/v1', '/author/(?P\d+)', [
'methods' => 'GET',
'callback' => function ($request) {
$author_id = (int) $request['id'];
$user = get_userdata($author_id);
if (!$user) return new WP_Error('not_found', 'User not found', ['status' => 404]);
return [
'id' => $user->ID,
'name' => $user->display_name,
'posts' => count_user_posts($author_id),
'role' => $user->roles[0] ?? 'subscriber',
];
},
'permission_callback' => '__return_true',
]);
访问:/wp-json/tech/v1/author/5
权限控制:不要裸奔
上面例子用了 permission_callback => '__return_true',意味着任何人可访问。生产环境必须加验证:
'permission_callback' => function ($request) {
// 只允许登录用户
return is_user_logged_in();
}
特定角色检查
'permission_callback' => function ($request) {
return current_user_can('edit_others_posts');
}
Token 验证(适用于 App/前端)
'permission_callback' => function ($request) {
$token = $request->get_header('X-Api-Token');
if (!$token) return false;
$user = get_users([
'meta_key' => 'api_token',
'meta_value' => hash('sha256', $token),
]);
return !empty($user);
}
分页:告别一次性拉取全部数据
WordPress REST API 默认分页,每页 10 条:
{
"headers": {
"X-WP-Total": 142,
"X-WP-TotalPages": 15
}
}
前端遍历所有页:
async function fetchAllPosts() {
const posts = [];
let page = 1;
while (true) {
const res = await fetch(`/wp-json/wp/v2/posts?page=${page}&per_page=100`);
const data = await res.json();
if (!data.length) break;
posts.push(...data);
page++;
}
return posts;
}
自定义分页参数:
register_rest_route('tech/v1', '/search', [
'methods' => 'GET',
'callback' => function ($request) {
$paged = (int) $request->get_param('page') ?: 1;
$per_page = min((int) $request->get_param('per_page') ?: 10, 100);
$query = new WP_Query([
's' => sanitize_text_field($request['s'] ?? ''),
'post_type' => 'post',
'paged' => $paged,
'posts_per_page' => $per_page,
]);
return [
'items' => array_map(fn($p) => [
'id' => $p->ID,
'title' => $p->post_title,
'link' => get_permalink($p->ID),
], $p->posts),
'total' => $p->found_posts,
'pages' => $p->max_num_pages,
];
},
]);
前端集成:用原生 fetch 还是 Axios
原生 fetch 够用,不要为了装 Axios 而装:
// 读公开数据,不需要认证
const res = await fetch('/wp-json/wp/v2/posts?per_page=5');
const posts = await res.json();
// 写操作需要 nonce
const nonce = document.querySelector('#wp-rest-nonce')?.content;
await fetch('/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': nonce,
},
body: JSON.stringify({
title: 'New Post',
content: 'Post body',
status: 'draft',
}),
});
nonce 在前端通过 wp_localize_script 或直接页面埋入:
wp_localize_script('my-app', 'wpApi', [
'root' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest'),
]);
React 集成示例
import { useEffect, useState } from 'react';
function PostList() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/wp-json/wp/v2/posts?per_page=10')
.then(r => r.json())
.then(data => {
setPosts(data);
setLoading(false);
});
}, []);
if (loading) return Loading...;
return (
{posts.map(p => (
-
{p.title.rendered}
))}
);
}
我踩过的 5 个坑
坑1:OPTIONS 请求返回 404
CORS 预检请求需要处理。在主题 functions.php:
add_filter('rest_pre_serve_request', function ($response) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type, X-Api-Token');
return $response;
}, 10, 2);
坑2:自定义端点返回 401 但不提示原因
在 permission_callback 里返回 WP_Error 可以附带状态码和消息:
return new WP_Error(
'unauthorized',
'API token missing or invalid',
['status' => 401]
);
坑3:wp_create_nonce 返回的值前端拿不到
wp_localize_script 的 nonce 字段名必须叫 nonce 才能被 wpApi.nonce 访问到:
wp_localize_script('my-app', 'wpApi', [
'nonce' => wp_create_nonce('wp_rest'),
// 叫 api_token 的话前端要用 wpApi.api_token
]);
坑4:自定义 post type 注册后无法通过 REST 访问
注册 CPT 时必须设置 show_in_rest => true:
register_post_type('book', [
'labels' => ['name' => 'Books'],
'public' => true,
'show_in_rest' => true, // ← 这个必须有
'rest_base' => 'books',
]);
坑5:生产环境 HTTPS 但 API 返回混合内容
WordPress 站点 HTTPS 化后,内部 REST API 调用仍然返回 HTTP 链接。在 wp-config.php:
$_SERVER['HTTPS'] = 'on';
define('FORCE_SSL_ADMIN', true);
或者通过 REST 响应 hook 修正:
add_filter('rest_pre_dispatch', function ($result, $server, $request) {
if (stripos($request->get_route(), '/wp-json/') === 0) {
add_filter('content_url', fn($url) => str_replace('http://', 'https://', $url));
}
return $result;
}, 10, 3);
版本控制:URL 前缀的作用
/wp-json/tech/v1/posts-stats ← v1,未来可以加 v2
/wp-json/wp/v2/posts ← WP 内置端点
tech/v1 是自定义命名空间,可以避免和 WP 内置端点冲突。WordPress REST API 默认会验证 namespace 是否符合 vendor/type 格式。
完整文件:把以上全部组合
'GET',
'callback' => function ($request) {
$posts = wp_count_posts();
return [
'publish' => $posts->publish,
'draft' => $posts->draft,
'total' => $posts->total,
];
},
'permission_callback' => function () {
return current_user_can('read');
},
]);
// CPT 注册示例(添加到 WordPress)
register_post_type('book', [
'public' => true,
'show_in_rest' => true,
'rest_base' => 'books',
]);
});
// CORS 头
add_filter('rest_pre_serve_request', function ($response) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type, X-Api-Token, X-WP-Nonce');
return $response;
}, 10, 2);
结语
WordPress REST API 的设计比想象中合理——自定义端点 + 权限回调 + namespace 版本控制,三个东西搞清楚就能做大部分集成工作。最常见的错误是把 show_in_rest 漏掉(导致 CPT 不可访问)和 CORS 没配(前端本地开发必踩)。
如果你在做一个前后端分离的 WordPress 项目,我建议先用 Postman 或 Insomnia 把端点调通,再接前端。不要边写前端边写后端,调试的时候会非常痛苦。
👉 立即体验 MiniMax API:https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link
本文验证版本:WordPress 6.9(2026-04-30 官方验证)、REST API 版本 2.0
🔗 Related Tech Articles
Deep dive into related technical topics: