REST API 文档

常见问题解答

💡 云策文档标注

概述

本文档针对使用 WordPress REST API 时可能遇到的常见问题提供解决方案,涵盖禁用 API、身份验证、内部请求、查询参数和服务器配置等方面。

关键要点

  • 不建议禁用 REST API,否则会破坏依赖 API 的 WordPress 管理功能,但可通过 rest_authentication_errors 过滤器要求所有请求进行身份验证。
  • 在插件中可使用 rest_do_request 从 PHP 内部发起 API 请求,但需注意 _embed 参数需手动调用 WP_REST_Server::response_to_data 函数处理。
  • ?filter 查询参数已从核心中移除,建议使用原生查询参数如 ?categories= 或 ?slug=,或通过 rest-filter 插件恢复功能。
  • 查询参数无效时,可能需检查服务器配置,例如 Nginx 中需确保 try_files 行包含 $is_args 以正确传递参数。
  • 身份验证失败可能因服务器(如 Apache 或 Nginx)剥离了 Authorization 头,需添加相应配置修复。
  • REST API 不验证 Origin 头,依赖 nonces 进行 CSRF 保护,如需限制跨域访问,可自定义 rest_pre_serve_request 过滤器中的 CORS 头。

代码示例

add_filter( 'rest_authentication_errors', function( $result ) {
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            __( 'You are not currently logged in.' ),
            array( 'status' => 401 )
        );
    }
    return $result;
});
$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( 'per_page', 20 );
$response = rest_do_request( $request );
$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$response = rest_do_request( $request );
$data = rest_get_server()->response_to_data( $response, true );
var_dump( $data['_embedded'] );

注意事项

  • rest_authentication_errors 过滤器的回调参数可为 null、布尔值或 WP_Error,需根据参数类型处理身份验证逻辑。
  • 内部请求中设置 _embed 参数无效,必须手动调用 WP_REST_Server::response_to_data 函数来获取嵌入数据。
  • 服务器配置问题(如 Nginx 的 try_files 行缺少 $is_args)可能导致查询参数不被识别,需调整配置以确保参数正确传递。
  • 在 CGI 环境中,Apache 或 Nginx 可能剥离 Authorization 头,需添加特定配置(如 SetEnvIf 或 fastcgi_pass_header)来保留头信息。
  • REST API 默认不验证 Origin 头,这允许公共端点从任何站点访问,但可通过自定义 rest_pre_serve_request 过滤器实施更严格的 CORS 策略。

📄 原文内容

This page provides solutions to some common questions and problems that may arise while using the API. If your question is not explained here it may have been answered in the WordPress support forums.

Can I disable the REST API?

You should not disable the REST API; doing so will break WordPress Admin functionality that depends on the API being active. However, you may use a filter to require that API consumers be authenticated, which effectively prevents anonymous external access. See below for more information.

Require Authentication for All Requests

You can require authentication for all REST API requests by adding an is_user_logged_in check to the rest_authentication_errors filter.

Note: The incoming callback parameter can be either null, a WP_Error, or a boolean. The type of the parameter indicates the state of authentication:

  • null: no authentication check has yet been performed, and the hook callback may apply custom authentication logic.
  • boolean: indicates a previous authentication method check was performed. Boolean true indicates the request was successfully authenticated, and boolean false indicates authentication failed.
  • WP_Error: Some kind of error was encountered.
add_filter( 'rest_authentication_errors', function( $result ) {
    // If a previous authentication check was applied,
    // pass that result along without modification.
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    // No authentication has been performed yet.
    // Return an error if user is not logged in.
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            __( 'You are not currently logged in.' ),
            array( 'status' => 401 )
        );
    }

    // Our custom authentication check should have no effect
    // on logged-in requests
    return $result;
});

Can I make API requests from PHP within a plugin?

Yes, you can! Use rest_do_request to make API requests internally within other WordPress code:

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
// Set one or more request query parameters
$request->set_param( 'per_page', 20 );
$response = rest_do_request( $request );

How do I use the _embed parameter on internal requests?

Setting the _embed param on the request object won’t work.

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( '_embed', 1 );
$response = rest_do_request( $request );

Instead, manually call the WP_REST_Server::response_to_data function.

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$response = rest_do_request( $request );
$data = rest_get_server()->response_to_data( $response, true );
var_dump( $data['_embedded'] );

What happened to the ?filter= query parameter?

When the REST API was merged into WordPress core the ?filter query parameter was removed to prevent future compatibility and maintenance issues. The ability to pass arbitrary WP_Query arguments to the API using a ?filter query parameter was necessary at the genesis of the REST API project, but most API response filtering functionality has been superseded by more robust query parameters like ?categories=, ?slug= and ?per_page=.

First-party query parameters should be used whenever possible. However, the rest-filter plugin restores the ability to pass arbitrary ?filter values in API request if needed.

Query parameters are not working

If you find that query parameters such as ?page=2 or ?_embed are not having any effect, your server may not be properly configured to detect them. If you are using Nginx to serve your website, look for a try_files line in your site configuration. If it looks like this:

try_files $uri $uri/ /index.php$args;

change it to this:

try_files $uri $uri/ /index.php$is_args$args;

Adding $is_args (which will print a ? character if query arguments are found) will allow WordPress to properly receive and interpret the query parameters.

Why is Authentication not working?

If you’re finding that you are sending Authentication headers but the request is not being accepted, and you are using a CGI environment, your webserver may be stripping the headers. Please try adding the appropriate configuration below to remedy this.

Apache

Add the following to a configuration file or .htaccess:

<IfModule mod_setenvif>
  SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
</IfModule>

Nginx

Add the following to your server configurations fastcgi section:

fastcgi_pass_header Authorization;

Why is the REST API not verifying the incoming Origin header? Does this expose my site to CSRF attacks?

Cross-Origin Resource Sharing (CORS) is a mechanism which allows a website to control which Origins (originating external sites) are allowed to access your site’s data. CORS prevents against a particular type of attack known as Cross-Site Request Forgery, or CSRF. However, WordPress has an existing CSRF protection mechanism which uses nonces. Tightening CORS restrictions would prevent some authentication methods, so the WordPress REST API uses nonces for CSRF protection instead of CORS.

Because the WordPress REST API does not verify the Origin header of incoming requests, public REST API endpoints may therefore be accessed from any site.

This is an intentional design decision, but if you wish to prevent your site from being accessed from unknown origins you may unhook the default rest_send_cors_headers function from the rest_pre_serve_request filter hook, then hook in your own function to that same filter to specify stricter CORS headers.