📚 相关阅读

← 返回首页

WordPress 建站指南 REST API 实战开发完整指南

WordPressREST APIAPI开发前端集成React

WordPress 从 4.7 开始内置 REST API,你不需要装任何插件就能让 WordPress 和任何前端框架对话。我花了 3 周把一个 WordPress 站点改成 React 前端 + WordPress 后端分离架构,中间踩了 5 个坑才摸清楚这套东西怎么正确使用。

什么时候该用 REST API 而不是 WP-CLI

WP-CLI 适合服务器端批量操作(比如批量更新插件、数据库替换)。REST API 适合:

如果你的需求只是"命令行操作 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 ( ); }

我踩过的 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:

WordPress REST API 实战开发完整指南
技术标签: rest api, api开发
WordPress REST API Development Complete Guide
技术标签: rest api, api development
WordPress REST API Development Complete Guide
技术标签: rest api, api development
🌐 WordPress Hosting
查看推荐 →