剖析 WordPress `get_rest_url()` 函数的源码:如何生成 REST API 的根 URL。

各位观众,下午好!今天,我们要扒一扒 WordPress 的 get_rest_url() 函数,看看它到底是如何变戏法,生成 REST API 的根 URL 的。准备好来一场源码探险了吗?系好安全带,我们出发!

1. 什么是 REST API 根 URL?为啥它这么重要?

在开始之前,先明确一下概念。REST API (Representational State Transfer Application Programming Interface) 简单来说,就是一套设计风格,让不同的应用之间可以通过 HTTP 协议互相交流。而根 URL,就是这套 API 的入口,就像一个网站的主页,你得先知道主页地址,才能访问里面的各种内容。

例如,WordPress 的 REST API 根 URL 可能是这样的:https://example.com/wp-json/。有了这个地址,你就可以用它来获取文章列表、创建新文章、更新用户信息等等。

没有根 URL,就像没有地图的寻宝游戏,你根本不知道从哪里开始。所以,get_rest_url() 才会如此重要。

2. get_rest_url() 的真面目:从源码看起

好了,废话不多说,直接上代码!get_rest_url() 函数的代码位于 wp-includes/rest-api.php 文件中。我们来仔细看看它的庐山真面目:

/**
 * Retrieves the REST API URL.
 *
 * @since 4.4.0
 *
 * @param string $path   Optional. REST route. Default empty.
 * @param string $scheme Optional. URL scheme context to generate.
 *                           Options are 'rest', 'admin', 'login', 'http', 'https',
 *                           'relative'. Default 'rest'.
 * @return string REST API URL.
 */
function get_rest_url( $path = null, $scheme = 'rest' ) {
    $url = home_url( '', $scheme );

    if ( empty( $path ) ) {
        return trailingslashit( $url . rest_get_url_prefix() );
    }

    return trailingslashit( $url . rest_get_url_prefix() . '/' . ltrim( $path, '/' ) );
}

看起来是不是没那么可怕?我们一行一行来分析:

  • /** ... */:这是 PHPDoc 风格的注释,说明了这个函数的作用、参数和返回值。
  • function get_rest_url( $path = null, $scheme = 'rest' ):定义了函数 get_rest_url(),它接受两个参数:
    • $path:可选参数,REST 路由,也就是 API 路径。默认值是 null,表示获取根 URL。
    • $scheme:可选参数,URL 协议类型,用于生成 URL。默认值是 rest
  • $url = home_url( '', $scheme );:这行代码调用了 home_url() 函数,获取站点首页的 URL。home_url() 的第二个参数 $scheme 决定了使用哪种协议(http 或 https)。
  • if ( empty( $path ) ) { ... }:判断 $path 是否为空。如果为空,说明我们只需要获取根 URL。
  • return trailingslashit( $url . rest_get_url_prefix() );:如果 $path 为空,这行代码将首页 URL 和 REST API 的 URL 前缀拼接起来,然后用 trailingslashit() 函数在末尾添加一个斜杠。rest_get_url_prefix() 函数我们稍后会详细讲解。
  • return trailingslashit( $url . rest_get_url_prefix() . '/' . ltrim( $path, '/' ) );:如果 $path 不为空,这行代码将首页 URL、REST API 的 URL 前缀和 $path 拼接起来,同样用 trailingslashit() 函数在末尾添加一个斜杠。ltrim( $path, '/' ) 用于移除 $path 开头的斜杠,避免出现多个连续的斜杠。

3. home_url() 的作用:找到你的家!

get_rest_url() 函数中,home_url() 扮演着非常重要的角色。它负责找到你网站的“家”,也就是首页的 URL。让我们来看看 home_url() 的源码(位于 wp-includes/link-template.php):

/**
 * Retrieves the URL for the current site where the front end is displayed.
 *
 * @since 2.2.0
 *
 * @param string $path   Optional. Path relative to the home URL. Default empty.
 * @param string $scheme Optional. Scheme to use. Default is the 'default' scheme.
 *                       See set_url_scheme() for accepted values.
 * @return string Home URL of the site.
 */
function home_url( $path = '', $scheme = null ) {
    return get_home_url( null, $path, $scheme );
}

实际上,home_url() 只是简单地调用了 get_home_url() 函数。这样做的好处是,可以将逻辑集中在 get_home_url() 中,方便维护和扩展。

我们再深入 get_home_url() 的源码:

/**
 * Retrieves the home URL for the current site.
 *
 * Returns the 'home' option with the appropriate protocol.
 *
 * @since 3.0.0
 *
 * @param int|null $blog_id Optional. The blog ID. Default null (current blog).
 * @param string   $path    Optional. Path relative to the home URL. Default empty.
 * @param string   $scheme  Optional. Scheme to use. Default is the 'default' scheme.
 *                          See set_url_scheme() for accepted values.
 * @return string Home URL of the site.
 */
function get_home_url( $blog_id = null, $path = '', $scheme = null ) {
    global $current_site;

    if ( empty( $blog_id ) ) {
        $blog_id = get_current_blog_id();
    }

    $orig_scheme = $scheme;

    if ( ! is_string( $path ) ) {
        $path = '';
    }

    $home = get_option( 'home' );

    if ( ! empty( $path ) && is_string( $path ) && '#' !== substr( $path, 0, 1 ) ) {
        $home = trailingslashit( $home );
    }

    if ( in_array( $scheme, array( 'http', 'https', 'relative' ), true ) ) {
        $home = set_url_scheme( $home, $scheme );
    } elseif ( 'rest' === $scheme ) {
        $home = set_url_scheme( $home, 'https' );
    } else {
        $home = set_url_scheme( $home );
    }

    if ( is_ssl() && 'http' === $orig_scheme ) {
        $home = str_replace( 'https://', 'http://', $home );
    }

    $home = untrailingslashit( $home );

    return $home . ( ( $path ) ? '/' . ltrim( $path, '/' ) : '' );
}

这下代码量有点多了,但别慌,我们慢慢分析:

  • $home = get_option( 'home' );:这行代码从 WordPress 的数据库中获取 home 选项的值。home 选项存储了网站的首页 URL。
  • if ( in_array( $scheme, array( 'http', 'https', 'relative' ), true ) ) { ... }:判断 $scheme 是否为 httphttpsrelative。如果是,则调用 set_url_scheme() 函数,设置 URL 的协议类型。
  • elseif ( 'rest' === $scheme ) { $home = set_url_scheme( $home, 'https' ); }:如果 $schemerest,则强制使用 https 协议。这是为了保证 REST API 的安全性。
  • else { $home = set_url_scheme( $home ); }:如果 $scheme 不是以上任何值,则使用默认的协议类型。
  • $home = untrailingslashit( $home );:移除 URL 末尾的斜杠。
  • return $home . ( ( $path ) ? '/' . ltrim( $path, '/' ) : '' );:将首页 URL 和 $path 拼接起来,并返回结果。

简单总结一下,get_home_url() 函数的作用就是:

  1. 从数据库中获取网站的首页 URL。
  2. 根据 $scheme 参数,设置 URL 的协议类型。
  3. 将首页 URL 和 $path 拼接起来,并返回结果。

4. rest_get_url_prefix() 的秘密:API 的身份证

回到 get_rest_url() 函数,我们还剩下一个关键函数没有讲解:rest_get_url_prefix()。这个函数的作用是获取 REST API 的 URL 前缀,也就是 wp-json

/**
 * Retrieves the REST API URL prefix.
 *
 * @since 4.4.0
 *
 * @return string REST prefix.
 */
function rest_get_url_prefix() {
    /**
     * Filters the REST API URL prefix.
     *
     * @since 4.4.0
     *
     * @param string $prefix URL prefix. Default 'wp-json'.
     */
    return apply_filters( 'rest_url_prefix', 'wp-json' );
}

这个函数非常简单,它只是返回一个字符串 'wp-json',并通过 apply_filters() 函数提供了一个过滤器 rest_url_prefix,允许开发者修改 REST API 的 URL 前缀。

这意味着,如果你不喜欢默认的 wp-json 前缀,你可以通过以下代码来修改它:

add_filter( 'rest_url_prefix', function( $prefix ) {
    return 'api'; // 将 URL 前缀修改为 'api'
});

这样,你的 REST API 根 URL 就会变成 https://example.com/api/

5. trailingslashit():斜杠的重要性

get_rest_url() 函数中,我们多次看到了 trailingslashit() 函数。这个函数的作用是在 URL 的末尾添加一个斜杠。

/**
 * Adds a trailing slash if not trailing slash or URL.
 *
 * This will remove trailing forward slashes if the string is a URL or path
 * with a query string.
 *
 * @since 3.0.0
 *
 * @param string $string What to add the trailing slash to.
 * @return string String with trailing slash added.
 */
function trailingslashit( $string ) {
    return untrailingslashit( $string ) . '/';
}

实际上,trailingslashit() 函数只是简单地调用了 untrailingslashit() 函数,移除 URL 末尾的斜杠,然后再添加一个斜杠。

那么,为什么要添加斜杠呢?这主要是为了规范化 URL,提高可读性。在 Web 开发中,通常建议在目录的 URL 末尾添加斜杠,以区分文件和目录。

6. 组合拳:get_rest_url() 的工作流程

现在,我们已经了解了 get_rest_url() 函数中使用的所有关键函数。让我们来总结一下它的工作流程:

  1. 获取网站的首页 URL,通过 home_url() 函数实现。home_url 内部调用 get_home_url,从数据库读取 home 选项,并根据传入的 $scheme 参数设置协议。
  2. 获取 REST API 的 URL 前缀,通过 rest_get_url_prefix() 函数实现。默认值为 wp-json,可以通过 rest_url_prefix 过滤器修改。
  3. 将首页 URL 和 REST API 的 URL 前缀拼接起来,如果需要,再加上指定的 $path
  4. 使用 trailingslashit() 函数在 URL 末尾添加一个斜杠。
  5. 返回最终的 REST API URL。

7. 举个栗子:实际应用场景

假设你的 WordPress 网站的 URL 是 https://example.com,你想获取 REST API 的根 URL,你可以这样调用 get_rest_url() 函数:

$rest_url = get_rest_url();
echo $rest_url; // 输出:https://example.com/wp-json/

如果你想获取文章列表的 URL,你可以这样调用 get_rest_url() 函数:

$posts_url = get_rest_url( 'wp/v2/posts' );
echo $posts_url; // 输出:https://example.com/wp-json/wp/v2/posts/

8. 源码剖析:表格总结

为了方便大家理解,我们用表格来总结一下 get_rest_url() 函数涉及的关键函数:

函数名 作用 源码位置
get_rest_url() 获取 REST API 的 URL。 wp-includes/rest-api.php
home_url() 获取网站的首页 URL。 wp-includes/link-template.php
get_home_url() 获取网站的首页 URL (实际执行函数)。 wp-includes/link-template.php
rest_get_url_prefix() 获取 REST API 的 URL 前缀(默认为 wp-json)。 wp-includes/rest-api.php
trailingslashit() 在 URL 末尾添加斜杠。 wp-includes/formatting.php
set_url_scheme() 设置 URL 的协议类型(http 或 https)。 wp-includes/functions.php
get_option() 从 WordPress 数据库中获取选项的值。 wp-includes/option.php
is_ssl() 检查当前请求是否使用了 SSL (HTTPS)。 wp-includes/functions.php
ltrim() 移除字符串开头的指定字符(默认为空格)。 PHP 内置函数
untrailingslashit() 移除字符串末尾的斜杠。 wp-includes/formatting.php
apply_filters() 应用过滤器,允许修改函数返回值。 wp-includes/plugin.php

9. 总结:掌握 get_rest_url(),玩转 WordPress REST API

通过今天的讲解,相信大家对 get_rest_url() 函数的实现原理有了更深入的理解。掌握了这个函数,你就掌握了 WordPress REST API 的入口,可以更轻松地开发基于 WordPress 的应用。

记住,阅读源码是提升编程技能的有效途径。希望今天的探险之旅对你有所帮助!下次再见!

发表回复

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