分析 WordPress `get_template_directory_uri()` 函数的源码:如何获取模板目录的 URL。

各位观众老爷,晚上好!今天咱们来聊聊 WordPress 里一个看似简单,实则暗藏玄机的函数——get_template_directory_uri()。这玩意儿经常出现在主题开发里,但你真的了解它吗?别急,咱们一层一层扒开它的源码,看看它到底是怎么拿到模板目录 URL 的。

开场白:URI 是个啥?

在深入源码之前,先简单复习一下 URI 的概念。URI (Uniform Resource Identifier),统一资源标识符,说白了,就是用来唯一标识互联网上资源的字符串。URL (Uniform Resource Locator) 是 URI 的一个子集,URL 不仅标识资源,还告诉你在哪里可以找到它,比如 https://www.example.com/image.jpg 就是一个 URL。get_template_directory_uri() 返回的就是模板目录的 URL。

第一幕:get_template_directory_uri() 的庐山真面目

直接上代码,看看 get_template_directory_uri() 函数长啥样:

<?php
/**
 * Retrieves URI of current theme directory.
 *
 * @since 1.5.0
 *
 * @return string URI of the current theme.
 */
function get_template_directory_uri() {
    return apply_filters( 'template_directory_uri', get_stylesheet_directory_uri() );
}

简洁明了!它仅仅调用了 get_stylesheet_directory_uri() 函数,然后用 apply_filters() 做了一个过滤。

划重点:apply_filters() 的作用

apply_filters() 是 WordPress 钩子机制的核心函数之一。它的作用是允许开发者在特定点修改数据。在这里,'template_directory_uri' 是一个过滤器名称,任何注册到这个过滤器的函数都会被执行,从而有机会修改 get_stylesheet_directory_uri() 返回的 URL。

第二幕:get_stylesheet_directory_uri() 的深入探险

接下来,我们需要深入 get_stylesheet_directory_uri() 函数,看看它又是如何工作的:

<?php
/**
 * Retrieves stylesheet directory URI for the current theme/child theme.
 *
 * @since 2.9.0
 *
 * @return string Stylesheet directory URI.
 */
function get_stylesheet_directory_uri() {
    static $stylesheet_dir_uri = '';

    if ( ! empty( $stylesheet_dir_uri ) ) {
        return $stylesheet_dir_uri;
    }

    $stylesheet_dir = get_stylesheet_directory();
    $theme_root_uri = get_theme_root_uri();
    $stylesheet_dir_uri = str_replace( WP_CONTENT_DIR, WP_CONTENT_URL, $stylesheet_dir );

    /**
     * Filters the stylesheet directory URI.
     *
     * @since 2.9.0
     *
     * @param string $stylesheet_dir_uri Stylesheet directory URI.
     * @param string $stylesheet_dir     Stylesheet directory.
     * @param string $theme_root_uri     Theme root URI.
     */
    $stylesheet_dir_uri = apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet_dir, $theme_root_uri );

    return $stylesheet_dir_uri;
}

这个函数稍微复杂一点,但逻辑还是很清晰的:

  1. 静态变量缓存: 使用 static $stylesheet_dir_uri = ''; 来缓存结果。这意味着函数第一次执行后,会将结果保存在 $stylesheet_dir_uri 变量中,下次再调用时,直接返回缓存的结果,避免重复计算。

  2. 获取样式表目录: 调用 get_stylesheet_directory() 获取当前主题或子主题的样式表目录的绝对路径

  3. 获取主题根目录 URI: 调用 get_theme_root_uri() 获取主题根目录的 URI。

  4. 替换路径: 使用 str_replace() 函数将样式表目录的绝对路径中的 WP_CONTENT_DIR 替换为 WP_CONTENT_URL,从而将绝对路径转换为 URI。

  5. 过滤: 再次使用 apply_filters() 允许开发者修改样式表目录的 URI。

第三幕:get_stylesheet_directory() 的寻根问底

现在,咱们要看看 get_stylesheet_directory() 函数是如何获取样式表目录的绝对路径的:

<?php
/**
 * Retrieves stylesheet directory for current theme/child theme.
 *
 * @since 1.5.0
 *
 * @return string Stylesheet directory.
 */
function get_stylesheet_directory() {
    static $stylesheet_dir = '';

    if ( ! empty( $stylesheet_dir ) ) {
        return $stylesheet_dir;
    }

    $stylesheet = get_stylesheet();
    $stylesheet_dir = WP_CONTENT_DIR . '/' . $stylesheet;

    /**
     * Filters the stylesheet directory.
     *
     * @since 2.2.0
     *
     * @param string $stylesheet_dir Stylesheet directory.
     * @param string $stylesheet     Stylesheet name.
     */
    $stylesheet_dir = apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet );

    return $stylesheet_dir;
}

这个函数和 get_stylesheet_directory_uri() 非常相似:

  1. 静态变量缓存: 同样使用 static $stylesheet_dir = ''; 来缓存结果。

  2. 获取样式表名称: 调用 get_stylesheet() 获取当前主题或子主题的样式表名称(即主题目录名)。

  3. 构建路径:WP_CONTENT_DIR 和样式表名称拼接起来,得到样式表目录的绝对路径。

  4. 过滤: 使用 apply_filters() 允许开发者修改样式表目录。

第四幕:get_stylesheet() 的终极揭秘

最后,咱们来看看 get_stylesheet() 函数是如何获取样式表名称的:

<?php
/**
 * Retrieves the name of the current stylesheet.
 *
 * The theme name, not the template name.
 *
 * @since 1.5.0
 *
 * @return string Stylesheet name.
 */
function get_stylesheet() {
    /**
     * Filters the name of the current stylesheet.
     *
     * @since 1.5.0
     *
     * @param string $stylesheet Stylesheet name.
     */
    return apply_filters( 'stylesheet', get_option( 'stylesheet' ) );
}

这个函数非常简单:

  1. 获取选项: 调用 get_option( 'stylesheet' ) 从 WordPress 选项表中获取 stylesheet 选项的值。这个选项存储了当前主题或子主题的样式表名称。

  2. 过滤: 使用 apply_filters() 允许开发者修改样式表名称。

第五幕:get_theme_root_uri() 的画龙点睛

get_stylesheet_directory_uri() 函数中,我们还用到了 get_theme_root_uri(),这个函数也很重要,因为它告诉我们主题根目录的 URI。

<?php
/**
 * Retrieves the URI for the themes directory.
 *
 * Does not have a trailing slash.
 *
 * @since 3.0.0
 *
 * @param string $stylesheet_or_template Optional. Stylesheet or template name of the theme.
 *                                       Default is the current theme.
 * @param string $theme_root             Optional. Absolute path to themes directory.
 *                                       Default is false.
 * @return string Themes directory URI.
 */
function get_theme_root_uri( $stylesheet_or_template = null, $theme_root = false ) {
    $themes_url = WP_CONTENT_URL . '/themes';

    if ( is_multisite() && ! is_subdomain_install() && is_main_site() ) {
        $original_blog_id = get_current_blog_id();
        switch_to_blog(1);
        $ms_dir = @get_site_option( 'ms_themes_network_dir' );
        switch_to_blog( $original_blog_id );

        if ( ! empty( $ms_dir ) )
            $themes_url = network_site_url( $ms_dir . '/themes' );
    }

    /**
     * Filters the URI for the themes directory.
     *
     * @since 3.0.0
     *
     * @param string      $themes_url             Themes directory URI.
     * @param string|null $stylesheet_or_template Stylesheet or template name of the theme.
     * @param string      $theme_root             Absolute path to themes directory.
     */
    return apply_filters( 'theme_root_uri', $themes_url, $stylesheet_or_template, $theme_root );
}

这个函数稍微复杂一点,但主要逻辑是:

  1. 构建默认 URI:WP_CONTENT_URL/themes 拼接起来,得到主题根目录的默认 URI。

  2. 处理多站点: 如果是多站点环境,并且不是子域名安装,并且是主站点,则尝试获取网络主题目录,并修改 URI。

  3. 过滤: 使用 apply_filters() 允许开发者修改主题根目录的 URI。

总结:代码流程图

为了更清晰地展示整个流程,咱们用一个流程图来总结一下:

graph TD
    A[get_template_directory_uri()] --> B(get_stylesheet_directory_uri());
    B --> C(get_stylesheet_directory());
    C --> D(get_stylesheet());
    D --> E{get_option('stylesheet')};
    C --> F[WP_CONTENT_DIR . '/' . $stylesheet];
    B --> G(get_theme_root_uri());
    B --> H[str_replace(WP_CONTENT_DIR, WP_CONTENT_URL, $stylesheet_dir)];
    A --> I[apply_filters('template_directory_uri')];
    B --> J[apply_filters('stylesheet_directory_uri')];
    C --> K[apply_filters('stylesheet_directory')];
    D --> L[apply_filters('stylesheet')];
    G --> M[apply_filters('theme_root_uri')];

代码示例:实际应用

现在,咱们来看几个实际应用的代码示例:

示例 1:获取主题目录 URL 并输出

<?php
$theme_url = get_template_directory_uri();
echo '<img src="' . $theme_url . '/images/logo.png" alt="Logo">';
?>

这个例子展示了如何使用 get_template_directory_uri() 获取主题目录 URL,然后用它来构建图片资源的 URL。

示例 2:使用过滤器修改主题目录 URL

<?php
add_filter( 'template_directory_uri', 'my_custom_template_directory_uri' );

function my_custom_template_directory_uri( $template_dir_uri ) {
    return 'https://cdn.example.com/themes/' . basename(get_template_directory());
}
?>

这个例子展示了如何使用 apply_filters() 修改主题目录 URL,将它指向 CDN 上的资源。basename(get_template_directory()) 用于获取当前主题的目录名。

示例 3:在子主题中使用 get_template_directory_uri()

在子主题中,get_template_directory_uri() 默认返回的是子主题的 URL。如果想要获取父主题的 URL,可以使用 get_template_directory()get_theme_root_uri() 手动构建:

<?php
$parent_theme_dir = get_template_directory();
$parent_theme_root_uri = get_theme_root_uri( get_template() );
$parent_theme_url = str_replace( WP_CONTENT_DIR, WP_CONTENT_URL, $parent_theme_dir );

echo '<img src="' . $parent_theme_url . '/images/logo.png" alt="Parent Logo">';
?>

表格:函数对比

为了更清晰地对比这些函数,咱们用一个表格来总结一下:

函数 返回值 说明
get_template_directory_uri() 当前主题或子主题的模板目录 URL 通常用于获取主题中的资源(如图片、CSS 文件等)的 URL。如果使用了子主题,它会返回子主题的 URL。
get_stylesheet_directory_uri() 当前主题或子主题的样式表目录 URL get_template_directory_uri() 类似,但更侧重于样式表目录。在大多数情况下,这两个函数返回相同的值,但如果子主题有自己的样式表目录,它们可能会不同。
get_template_directory() 当前主题或子主题的模板目录的绝对路径 返回的是文件系统的路径,而不是 URL。通常用于读取主题中的文件内容。
get_stylesheet_directory() 当前主题或子主题的样式表目录的绝对路径 get_template_directory() 类似,但更侧重于样式表目录。
get_stylesheet() 当前主题或子主题的样式表名称(即主题目录名) 用于获取当前主题或子主题的目录名,这个名称通常与样式表文件的名称相同。
get_theme_root_uri() 主题根目录的 URL (通常是 WP_CONTENT_URL/themes) 用于获取 WordPress 主题目录的 URL。在多站点环境中,这个函数可能会返回不同的值,取决于网络设置。
WP_CONTENT_DIR WordPress 内容目录的绝对路径(例如 /var/www/html/wp-content 是一个常量,定义了 WordPress 内容目录的绝对路径。这个目录包含了主题、插件、上传文件等。
WP_CONTENT_URL WordPress 内容目录的 URL(例如 https://example.com/wp-content 是一个常量,定义了 WordPress 内容目录的 URL。

Q & A 环节

  • Q: 为什么要有 apply_filters() 这种机制?

    A: apply_filters() 允许开发者在不修改核心代码的情况下,扩展和定制 WordPress 的功能。这使得 WordPress 非常灵活和可扩展。

  • Q: 在什么情况下 get_template_directory_uri()get_stylesheet_directory_uri() 会返回不同的值?

    A: 这种情况通常发生在子主题中,并且子主题覆盖了父主题的模板。在这种情况下,get_template_directory_uri() 返回父主题的 URL,而 get_stylesheet_directory_uri() 返回子主题的 URL。

  • Q: WP_CONTENT_DIRWP_CONTENT_URL 这两个常量在哪里定义的?

    A: 这两个常量通常在 wp-config.php 文件中定义。如果没有定义,WordPress 会使用默认值。

结语

好了,今天的 get_template_directory_uri() 源码分析就到这里了。希望通过这次深入的剖析,大家对这个函数有了更清晰的认识。记住,理解源码是成为 WordPress 大神的必经之路! 下次再见!

发表回复

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