一个常见需求:客户想要个小程序,同时还要有官网。两套后台维护两份数据?太累。
更划算的做法:WordPress 当内容和数据的后台,小程序/App 通过接口读数据。内容只维护一份,两端同步。
WordPress 自带 REST API,开箱可用,不用装插件。这篇讲怎么用它。
一、先看看 API 长什么样
直接在浏览器打开:
https://你的域名/wp-json/wp/v2/posts
你会看到一堆 JSON 数据——这就是你最新的文章,机器可读的格式。
常用接口
| 接口 | 返回什么 |
|---|---|
/wp-json/wp/v2/posts |
文章列表 |
/wp-json/wp/v2/posts/123 |
ID 为 123 的单篇文章 |
/wp-json/wp/v2/pages |
页面 |
/wp-json/wp/v2/categories |
分类 |
/wp-json/wp/v2/media |
媒体文件 |
/wp-json/wp/v2/users |
用户(注意:默认公开,见安全部分) |
WooCommerce 也自带接口:/wp-json/wc/store/products(新版)或 /wp-json/wc/v3/products(旧版,需要密钥)。
常用参数
# 只要 5 条 /wp-json/wp/v2/posts?per_page=5 # 分页(第 2 页) /wp-json/wp/v2/posts?page=2 # 按分类筛选(分类 ID 为 3) /wp-json/wp/v2/posts?categories=3 # 搜索关键词 /wp-json/wp/v2/posts?search=wordpress # 只要某些字段(减少传输量,很重要) /wp-json/wp/v2/posts?_fields=id,title,link,excerpt # 排序 /wp-json/wp/v2/posts?orderby=date&order=desc
_fields 参数对性能影响很大。默认一篇文章返回完整数据(含正文、所有 meta),几十 KB;只要几个字段能缩到 1KB 以内。移动端一定要用。
二、认证:读和写的区别
读取公开内容:不需要认证
已发布的文章、分类这些,任何人都能读,不需要登录。这对小程序场景刚好——访客看内容不需要身份。
写入数据(发布文章、下单):需要认证
三种方式:
| 方式 | 适合场景 | 复杂度 |
|---|---|---|
| Application Passwords | 小程序/App 后台操作 | 低(推荐) |
| JWT 插件 | 需要用户登录体系 | 中 |
| Cookie + Nonce | 同一站点内的 Ajax 请求 | 低(仅限本站) |
Application Passwords(推荐给小程序场景)
后台 → 用户 → 你的账号 → 往下找到「应用程序密码」→ 生成一个。
会得到一串类似 xxxx xxxx xxxx xxxx xxxx xxxx 的密码(空格是为了好读,实际用的时候可以去掉)。
调用时:
curl -u "用户名:应用程序密码" \
-X POST https://你的域名/wp-json/wp/v2/posts \
-H "Content-Type: application/json" \
-d '{"title":"测试标题","status":"draft"}'
两个前提:
- 站点必须启用 HTTPS(WordPress 默认不允许在 HTTP 下使用 Application Passwords)
- 这个密码等同于你的账号权限,泄露了别人就能以你的身份操作网站。不要写进小程序前端代码里
三、给 API 加自定义字段
默认的接口不包含你的自定义字段(比如 ACF 建的字段)。两种加法:
方法一:让 ACF 字段出现在 API 里
add_action( 'rest_api_init', function() {
register_rest_field( 'post', 'acf_fields', array(
'get_callback' => function( $post ) {
return get_fields( $post['id'] );
},
'schema' => null,
) );
});
之后接口返回里会多一个 acf_fields 对象,包含所有自定义字段。
方法二:注册 CPT 时开启 REST 支持
register_post_type( 'case', array(
'public' => true,
'show_in_rest' => true, // 关键:这一行
'rest_base' => 'cases', // 接口路径,默认用 CPT 名
// ...
) );
加了 show_in_rest 之后,这个 CPT 就有自己的接口:/wp-json/wp/v2/cases。
自定义字段也要单独开:
register_post_meta( 'case', '_client_name', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
四、自定义接口(写自己的业务逻辑)
有时候现成的接口不够用——比如你需要「一次性返回首页所有区块的数据」,减少请求次数。
add_action( 'rest_api_init', function() {
register_rest_route( 'myapp/v1', '/home', array(
'methods' => 'GET',
'callback' => 'myapp_home_data',
'permission_callback' => '__return_true', // 公开访问
) );
});
function myapp_home_data() {
$banners = get_posts( array(
'post_type' => 'banner',
'posts_per_page' => 5,
) );
$products = wc_get_products( array( 'limit' => 8 ) );
return array(
'banners' => array_map( function( $p ) {
return array(
'title' => $p->post_title,
'image' => get_the_post_thumbnail_url( $p->ID, 'full' ),
);
}, $banners ),
'products' => array_map( function( $pr ) {
return array(
'id' => $pr->get_id(),
'name' => $pr->get_name(),
'price' => $pr->get_price(),
'image' => wp_get_attachment_url( $pr->get_image_id() ),
);
}, $products ),
);
}
访问 /wp-json/myapp/v1/home 就能拿到一次打包好的首页数据。对移动端性能友好——一个请求搞定,不用调七八次接口。
五、必须做的安全设置
接口开着,等于把你的数据暴露出来。有几件事必须做。
1. 关闭用户枚举(重要)
访问 /wp-json/wp/v2/users,默认会返回所有用户的用户名。攻击者拿到用户名就能针对性爆破密码。
add_filter( 'rest_endpoints', function( $endpoints ) {
if ( isset( $endpoints['/wp/v2/users'] ) ) {
unset( $endpoints['/wp/v2/users'] );
}
if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
}
return $endpoints;
});
2. 给写操作加权限检查
自定义接口里 permission_callback 不要无脑写 __return_true——那等于任何人都能调用。
'permission_callback' => function() {
return current_user_can( 'publish_posts' );
},
3. 限制接口访问频率
接口被刷会导致服务器压力剧增。在 nginx 层做限流,或者用插件。
4. 敏感字段不要输出
返回数据前过滤一遍,别把内部字段(成本价、客户信息、内部备注)吐出去。尤其是电商站——接口里泄露成本价是真实发生过的事故。
六、性能:接口慢怎么办
接口慢的原因和页面慢一样,主要是数据库查询和 PHP 执行。
1. 用 _fields 减少数据量
前面提过,效果最明显。
2. 加缓存
add_action( 'rest_api_init', function() {
register_rest_route( 'myapp/v1', '/home', array(
'methods' => 'GET',
'callback' => function() {
$cache = get_transient( 'myapp_home_data' );
if ( $cache !== false ) {
return $cache;
}
$data = myapp_build_home_data();
set_transient( 'myapp_home_data', $data, 5 * MINUTE_IN_SECONDS );
return $data;
},
'permission_callback' => '__return_true',
) );
});
用 transient 缓存 5 分钟,接口响应从几百毫秒降到几十毫秒。内容更新时清一下缓存即可。
3. 装 Redis 对象缓存
对 API 同样有效,尤其是列表接口。
七、什么时候不该用 WordPress REST API
诚实地说,WordPress 的 API 有它的局限:
- 高并发场景——WordPress 每个请求都要加载完整内核,比专门的 API 框架重得多。日活几万的应用不建议用
- 复杂的查询逻辑——WordPress 的查询参数比较基础,复杂的多表联查不如直接写 SQL 或者用专门的后端
- 实时性要求高——比如聊天、实时数据,WordPress 不合适
适合它的场景:中小企业官网 + 小程序、内容型 App、内部工具、订单量不大的电商。这些场景下它省下的开发成本非常可观。
最后
用 WordPress 当后端,最大的价值不是技术多先进,而是:
- 后台是现成的——不用从零开发管理界面,客户自己也就会用
- 内容维护成本低——发文章、传图片都是成熟体验
- 生态丰富——WooCommerce、多语言、SEO 插件都是现成的
对一个预算有限的中小项目来说,这个组合能省掉几万块的后台开发费用。而它多出来的那点性能开销,在这个量级下完全可以忽略。