分析 WordPress `rest_get_all_endpoints()` 函数源码:如何获取所有注册的 REST API 端点。

嘿,大家好,欢迎来到今天的“扒光 WordPress REST API”讲座。今天咱们要聊聊一个非常关键的函数:rest_get_all_endpoints()。这个函数就像是 WordPress REST API 的地图,它能告诉你所有的“宝藏”都藏在哪里。

准备好了吗?咱们这就开始寻宝!

第一站:rest_get_all_endpoints() 函数的真面目

首先,让我们看看 rest_get_all_endpoints() 函数究竟长什么样。这个函数定义在 wp-includes/rest-api.php 文件中,别害怕,咱们一步步来拆解它。

/**
 * Gets all registered REST API endpoints.
 *
 * @since 4.4.0
 *
 * @global WP_REST_Server $wp_rest_server REST server instance.
 *
 * @return array Registered REST API endpoints, organized by route.
 */
function rest_get_all_endpoints() {
    global $wp_rest_server;

    if ( empty( $wp_rest_server ) ) {
        return array();
    }

    return $wp_rest_server->get_routes();
}

是不是很简单? 实际上,它主要做了两件事:

  1. 获取全局 $wp_rest_server 对象: global $wp_rest_server; 这一行代码声明我们要使用全局的 $wp_rest_server 变量。这个变量是 WP_REST_Server 类的实例,负责管理所有的 REST API 路由。
  2. 调用 $wp_rest_server->get_routes() return $wp_rest_server->get_routes(); 这行代码才是关键。它调用了 $wp_rest_server 对象的 get_routes() 方法,这个方法会返回一个包含所有已注册 REST API 端点的数组。

所以,rest_get_all_endpoints() 本身只是一个“传话筒”,真正的核心逻辑在 WP_REST_Server 类的 get_routes() 方法中。

第二站:深入 WP_REST_Server::get_routes()

现在,我们得去 WP_REST_Server 类里一探究竟。这个类也定义在 wp-includes/rest-api.php 文件中。

/**
 * Retrieves all registered routes.
 *
 * @since 4.4.0
 *
 * @return array Key-value array of registered routes.
 */
public function get_routes() {
    return $this->endpoints;
}

哇哦,更简单了!get_routes() 方法直接返回了 $this->endpoints 这个属性。 $endpointsWP_REST_Server 类的一个私有属性,它存储了所有注册的 REST API 路由。

所以,真正的秘密就藏在 $this->endpoints 里!

第三站:$endpoints 的结构:REST API 的藏宝图

$endpoints 属性是一个多维数组,它的结构是这样的:

[
    '/route/path' => [
        [
            'methods'  => [ 'GET', 'POST', ... ],
            'callback' => 'function_name', // 或者 [ $object, 'method_name' ]
            'args'     => [ /* 参数定义 */ ],
            'permission_callback' => 'function_name',
            // ... 其他属性
        ],
        [
            // 针对同一个路由,可能有不同的方法和回调
        ],
    ],
    '/another/route' => [
        // ...
    ],
]

让我们用一个表格来更清晰地展示这个结构:

键 (Key) 值 (Value)
/route/path 一个字符串,表示 REST API 的路由路径,例如 /wp/v2/posts
[ ... ] 一个数组,包含了针对该路由的所有注册信息。 每个元素都是一个数组,代表一个特定的方法 (GET, POST, 等) 和回调函数。
methods 一个数组,包含了该路由支持的 HTTP 方法,例如 ['GET', 'POST']
callback 一个回调函数,当请求匹配到该路由和方法时,会执行这个函数。 可以是函数名 (字符串) 或者一个数组 [ $object, 'method_name' ],表示对象的方法。
args 一个数组,定义了该路由的参数。 每个参数都有自己的属性,例如 type (参数类型), required (是否必须), validate_callback (验证回调函数), sanitize_callback (清理回调函数) 等。
permission_callback 一个回调函数,用于检查用户是否有权限访问该路由。 如果该函数返回 trueWP_REST_Response 对象,则允许访问;否则,拒绝访问。
schema 一个数组或回调函数,用于描述该路由的请求和响应的 JSON Schema。 这有助于客户端了解如何使用该 API 以及期望的响应格式。 从 WordPress 5.5 开始,推荐使用 schema 而不是 args 来定义参数。
还有其他一些属性,例如 accept_json (是否接受 JSON 请求), show_in_index (是否显示在 API 索引中) 等。

举个栗子:/wp/v2/posts 路由

让我们以 /wp/v2/posts 这个常见的路由为例,看看它的 $endpoints 数组可能长什么样:

[
    '/wp/v2/posts' => [
        [
            'methods'  => [ 'GET' ],
            'callback' => 'WP_REST_Posts_Controller->get_items',
            'permission_callback' => 'WP_REST_Posts_Controller->get_items_permissions_check',
            'args'     => [
                'context' => [
                    'default' => 'view',
                ],
                'page' => [
                    'type' => 'integer',
                    'default' => 1,
                ],
                // ... 其他参数
            ],
            'schema' => 'WP_REST_Posts_Controller->get_item_schema',
        ],
        [
            'methods'  => [ 'POST' ],
            'callback' => 'WP_REST_Posts_Controller->create_item',
            'permission_callback' => 'WP_REST_Posts_Controller->create_item_permissions_check',
            'args'     => [
                'title' => [
                    'type' => 'string',
                    'required' => true,
                ],
                'content' => [
                    'type' => 'string',
                ],
                // ... 其他参数
            ],
            'schema' => 'WP_REST_Posts_Controller->get_item_schema',
        ],
    ],
]

在这个例子中,/wp/v2/posts 路由支持两种方法:GET (获取文章列表) 和 POST (创建新文章)。 每种方法都有自己的回调函数、权限检查函数和参数定义。

第四站:如何使用 rest_get_all_endpoints() 获取所有端点

现在,我们已经了解了 rest_get_all_endpoints() 函数的作用和 $endpoints 数组的结构,接下来看看如何实际使用它。

$all_endpoints = rest_get_all_endpoints();

// 遍历所有端点
foreach ( $all_endpoints as $route => $handlers ) {
    echo "Route: " . esc_html( $route ) . "<br>";

    // 遍历该路由的所有处理程序
    foreach ( $handlers as $handler ) {
        echo "&nbsp;&nbsp;Methods: " . implode( ', ', $handler['methods'] ) . "<br>";
        echo "&nbsp;&nbsp;Callback: ";

        if ( is_string( $handler['callback'] ) ) {
            echo esc_html( $handler['callback'] ) . "<br>";
        } elseif ( is_array( $handler['callback'] ) ) {
            echo esc_html( get_class( $handler['callback'][0] ) . '->' . $handler['callback'][1] ) . "<br>";
        } else {
            echo "Unknown callback type<br>";
        }

        echo "&nbsp;&nbsp;Permission Callback: ";

        if ( is_string( $handler['permission_callback'] ) ) {
            echo esc_html( $handler['permission_callback'] ) . "<br>";
        } elseif ( is_array( $handler['permission_callback'] ) ) {
            echo esc_html( get_class( $handler['permission_callback'][0] ) . '->' . $handler['permission_callback'][1] ) . "<br>";
        } else {
            echo "Unknown permission callback type<br>";
        }

        echo "&nbsp;&nbsp;Arguments:<br>";
        if ( ! empty( $handler['args'] ) ) {
            echo "<pre>";
            print_r( $handler['args'] );
            echo "</pre>";
        } else {
            echo "&nbsp;&nbsp;None<br>";
        }
    }

    echo "<br>";
}

这段代码会遍历所有的 REST API 端点,并打印出每个路由的路径、支持的方法、回调函数、权限检查函数和参数定义。 你可以将这段代码放在你的 WordPress 主题的 functions.php 文件中,或者创建一个自定义插件来运行它。 记得在运行后移除这段代码,因为它可能会暴露敏感信息。

第五站:为什么要获取所有端点?

你可能会问,为什么要费这么大劲获取所有的 REST API 端点呢? 其实有很多用途:

  • 调试和学习: 通过查看所有端点,你可以更好地了解 WordPress REST API 的结构和功能,方便调试和学习。
  • 自定义开发: 在自定义 REST API 客户端时,你可以使用这些信息来生成 API 文档、构建请求和处理响应。
  • 安全审计: 你可以检查所有端点的权限设置,确保没有未授权的访问。
  • 自动化测试: 你可以使用这些信息来编写自动化测试脚本,验证 API 的功能是否正常。
  • 插件开发: 查找某个特定插件是否注册了 API 接口,以及这些接口的参数和权限。

第六站:rest_get_server():通往 $wp_rest_server 的另一扇门

除了直接使用全局 $wp_rest_server 变量,你还可以使用 rest_get_server() 函数来获取 WP_REST_Server 实例。

/**
 * Gets the REST server instance.
 *
 * @since 4.4.0
 *
 * @return WP_REST_Server Server instance.
 */
function rest_get_server() {
    global $wp_rest_server;

    if ( empty( $wp_rest_server ) ) {
        $wp_rest_server = new WP_REST_Server;

        /**
         * Fires after the REST API is initialized.
         *
         * @since 4.4.0
         *
         * @param WP_REST_Server $wp_rest_server REST server instance.
         */
        do_action( 'rest_api_init', $wp_rest_server );
    }

    return $wp_rest_server;
}

rest_get_server() 函数会返回全局 $wp_rest_server 对象,如果 $wp_rest_server 对象还没有被创建,它会先创建一个新的 WP_REST_Server 实例,并触发 rest_api_init action。

所以,你可以这样使用 rest_get_server() 来获取所有端点:

$server = rest_get_server();
$all_endpoints = $server->get_routes();

// 接下来就可以像前面一样遍历 $all_endpoints 了

第七站:rest_api_init action:REST API 的启动仪式

rest_get_server() 函数中提到了 rest_api_init action。 这个 action 是在 REST API 初始化之后触发的,你可以在这个 action 中注册你自己的 REST API 路由。

add_action( 'rest_api_init', 'my_register_rest_route' );

function my_register_rest_route() {
    register_rest_route( 'my-plugin/v1', '/my-endpoint', array(
        'methods'  => 'GET',
        'callback' => 'my_endpoint_callback',
    ) );
}

function my_endpoint_callback( WP_REST_Request $request ) {
    return array( 'message' => 'Hello from my endpoint!' );
}

这段代码会在 my-plugin/v1 命名空间下注册一个名为 /my-endpoint 的 REST API 路由。 当用户访问这个路由时,会执行 my_endpoint_callback 函数,并返回一个包含 "Hello from my endpoint!" 消息的 JSON 响应。

总结:REST API 的寻宝之旅

今天,我们一起深入探索了 WordPress REST API 的核心函数 rest_get_all_endpoints()。 我们了解了它的作用、WP_REST_Server 类的结构以及 $endpoints 数组的格式。 我们还学习了如何使用 rest_get_all_endpoints()rest_get_server() 函数来获取所有注册的 REST API 端点,以及如何使用 rest_api_init action 来注册你自己的 REST API 路由。

希望这次寻宝之旅让你对 WordPress REST API 有了更深入的了解。 记住,REST API 是 WordPress 的强大武器,掌握它,你就能创造出更强大的 WordPress 应用!

下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注