剖析 WordPress `get_template_part()` 函数源码:它在查找模板文件时与 `locate_template()` 的关系。

观众朋友们,大家好!我是今天的主讲人,很高兴能和大家一起探讨 WordPress 里一个非常重要,但又容易被忽视的函数:get_template_part()。 咱们今天就来庖丁解牛,把它和它的好搭档 locate_template() 彻底扒个精光!

开场白:模板,模板,到底在哪里?

在 WordPress 的世界里,模板就是我们网站的骨架和皮肤,决定了网站的整体外观和布局。 而 get_template_part() 函数,就是那个负责把这些骨架和皮肤的各个部分组装起来的关键工具。 想象一下,你的网站是一个乐高积木,get_template_part() 就像你的手,负责抓取不同的积木块 (模板文件),然后把它们拼接到一起。

但是,问题来了:WordPress 这么聪明,它是怎么知道哪些文件是模板,又该去哪里找到它们呢? 这就轮到 locate_template() 出场了!

get_template_part():组装大师

get_template_part() 函数的职责很简单:加载并包含一个模板文件。 它的基本语法是:

<?php get_template_part( string $slug, string|null $name = null, array $args = array() ); ?>
  • $slug (必须): 这是模板文件名的通用部分,相当于乐高积木的种类。 比如,你想加载一个名为 content-page.php 的文件,$slug 就是 content
  • $name (可选): 这是模板文件名的特定部分,相当于同种类乐高积木的不同型号。 如果你想加载 content-page.php$name 就是 page。 如果 $name 为空,WordPress 会尝试加载 content.php
  • $args (可选): 这是一个关联数组,用于传递变量到模板文件中。 这个我们后面会详细讲。

举个栗子:

<?php get_template_part( 'content', 'page' ); ?>

这行代码会尝试加载 content-page.php 文件。 WordPress 会先找 content-page.php,如果找不到,就找 content.php

locate_template():寻宝猎人

locate_template() 函数的任务是:根据你提供的文件名,在主题的各个目录中查找对应的模板文件。 它会按照一定的优先级顺序搜索,直到找到匹配的文件为止。

<?php locate_template( string|string[] $template_names, bool $load = false, bool $require_once = true ) : string ?>
  • $template_names (必须): 一个字符串或字符串数组,包含要查找的模板文件名。 注意,这里要包含 .php 扩展名。
  • $load (可选): 一个布尔值,如果设置为 true,则找到文件后立即加载它。 默认值为 false,只返回文件的路径。
  • $require_once (可选): 一个布尔值,如果 $loadtrue,则决定是否使用 require_once 加载文件。 默认值为 true

举个栗子:

<?php
$template = locate_template( array( 'content-page.php', 'content.php' ) );

if ( $template ) {
    include( $template ); // 或者 require( $template );
} else {
    echo '找不到模板文件!';
}
?>

这段代码首先使用 locate_template() 查找 content-page.phpcontent.php 文件。 如果找到了,就把它的路径存储在 $template 变量中。 然后,我们检查 $template 是否为空,如果不为空,就使用 include() 函数加载这个模板文件。

get_template_part()locate_template() 的关系:黄金搭档

现在,我们来揭开它们之间的神秘关系。 get_template_part() 内部其实就是调用了 locate_template() 函数! 简单来说,get_template_part() 负责构建要查找的文件名,然后把这些文件名交给 locate_template() 去搜索。 找到文件后,get_template_part() 会使用 include() 函数加载这个文件。

我们可以简化一下 get_template_part() 的内部逻辑,大概是这样的:

function my_get_template_part( $slug, $name = null, $args = array() ) {
    $templates = array();
    $name_slug = (string) $name;

    if ( '' !== $name_slug ) {
        $templates[] = "{$slug}-{$name_slug}.php";
    }

    $templates[] = "{$slug}.php";

    $located = locate_template( $templates, true, false ); // 注意这里 $load = true

    if ( $args && is_array( $args ) ) {
        extract( $args ); // 将数组键名作为变量名
    }

    if ( ! empty( $located ) ) {
        // Do some actions before template inclusion
        do_action( 'get_template_part_' . $slug, $slug, $name );

        // Include the template (locate_template already did this when $load was true)
        //include( $located );  // 这一步 locate_template 已经做了

        // Do some actions after template inclusion
        do_action( 'after_get_template_part_' . $slug, $slug, $name );
    }
}

重点:

  1. get_template_part() 根据 $slug$name 构建一个模板文件名数组。
  2. 它调用 locate_template() 函数,并将 $load 参数设置为 true。 这意味着 locate_template() 在找到文件后会立即加载它,而不需要 get_template_part() 再次使用 include()
  3. get_template_part() 提供了 get_template_part_{$slug}after_get_template_part_{$slug} 两个 action hook,允许你在模板文件加载前后执行自定义代码。
  4. get_template_part 使用了 extract( $args ) 函数。 这会将 $args 数组中的键名提取为变量名,方便在模板文件中使用。

模板文件搜索优先级:寻宝图

locate_template() 函数在搜索模板文件时,会按照一定的优先级顺序进行查找。 这个顺序非常重要,因为它决定了哪个模板文件会被最终加载。

搜索顺序如下:

  1. 子主题目录: 如果你正在使用子主题,WordPress 会首先在子主题的目录中查找模板文件。 这意味着你可以通过在子主题中创建同名文件来覆盖父主题的模板。
  2. 父主题目录: 如果在子主题目录中找不到模板文件,WordPress 会在父主题的目录中查找。
  3. WP_TEMPLATE_PATH 目录: 如果定义了 WP_TEMPLATE_PATH 常量,WordPress 也会在这个目录中查找模板文件。(不常用)

更详细一点,我们可以用表格来总结一下:

目录 优先级 说明
get_stylesheet_directory() 1 子主题的目录 (如果存在)。 使用 get_stylesheet_directory() 获取子主题的绝对路径。 例如:/wp-content/themes/my-child-theme
get_template_directory() 2 父主题的目录。 使用 get_template_directory() 获取父主题的绝对路径。 例如:/wp-content/themes/my-parent-theme
自定义模板目录 (通过过滤器修改) 3 可以通过 template_include 过滤器自定义模板目录,优先级高于默认的父主题目录。
WP_TEMPLATE_PATH (如果已定义) 4 这是一个可选的常量,用于指定额外的模板目录。 不常用,一般不建议使用,因为它会影响主题的可移植性。
默认 WordPress 模板文件 (在 WordPress 核心代码中) 5 如果在以上所有目录中都找不到模板文件,WordPress 会尝试加载默认的模板文件。 这些文件通常位于 wp-includes/template-loader.php 中。 比如,如果找不到 page.php,WordPress 可能会加载 index.php这个优先级最低,除非你的主题完全没有 page.php,否则不会用到。

$args 参数:模板之间的秘密通道

还记得 get_template_part() 函数的第三个参数 $args 吗? 它是一个关联数组,允许你向模板文件传递变量。 这是一种非常优雅的方式,可以避免在模板文件中直接访问全局变量。

举个栗子:

在你的主题文件中:

<?php
$my_variable = 'Hello from the parent theme!';

get_template_part( 'template-parts/my-template', null, array( 'my_variable' => $my_variable ) );
?>

template-parts/my-template.php 文件中:

<?php
if ( isset( $my_variable ) ) {
    echo '<p>' . esc_html( $my_variable ) . '</p>';
} else {
    echo '<p>Variable not set!</p>';
}
?>

在这个例子中,我们把 $my_variable 传递给了 my-template.php 文件。 在 my-template.php 文件中,我们就可以直接使用 $my_variable 变量了。 值得注意的是,get_template_part() 内部使用了 extract() 函数,将 $args 数组的键名提取为变量名。

注意:

  • 虽然 extract() 函数很方便,但也存在一定的安全风险。 如果你的 $args 数组中包含了用户输入的数据,可能会导致变量覆盖漏洞。 因此,在使用 extract() 函数时,一定要小心谨慎,确保数据的安全性。
  • 为了避免变量冲突,建议给 $args 数组的键名添加前缀。 比如,你可以使用 my_template_variable 代替 my_variable

实际应用:让你的网站更灵活

get_template_part() 函数在实际开发中有很多用途。 比如:

  • 创建可重用的模板片段: 你可以把网站的某些部分 (比如页眉、页脚、侧边栏) 封装成独立的模板文件,然后使用 get_template_part() 函数在不同的页面中加载这些模板片段。 这样可以减少代码重复,提高代码的可维护性。
  • 根据不同的条件加载不同的模板: 你可以根据用户的角色、页面类型等条件,使用 get_template_part() 函数加载不同的模板文件。 这样可以实现更灵活的页面布局。
  • 构建复杂的页面布局: 你可以使用 get_template_part() 函数将页面分解成多个小的模板片段,然后把这些片段组合在一起,构建出复杂的页面布局。

总结:

get_template_part()locate_template() 就像一对默契的搭档,共同负责加载 WordPress 模板文件。 get_template_part() 负责构建文件名并加载文件,而 locate_template() 负责在主题目录中查找文件。 掌握了这两个函数,你就掌握了 WordPress 模板系统的一把钥匙,可以更灵活地控制网站的外观和布局。

希望今天的讲解对大家有所帮助! 谢谢大家!

发表回复

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