各位观众老爷们,大家好!今天咱们来聊聊 WordPress 模板里一个非常关键的函数:get_template_part()
。 别看它名字平平无奇,但它却是 WordPress 主题模块化的基石。 咱们不光要用它,还要扒开它的衣服,看看它到底是怎么工作的。核心就在于它如何通过 locate_template()
找到咱们想要的模板文件。
一、get_template_part()
:主题模块化的利器
简单来说,get_template_part()
的作用就是加载一个模板文件,然后把这个模板文件的内容插入到当前正在执行的模板中。 想象一下,你在制作一个博客主题,文章列表、侧边栏、页脚,这些都是可以重复使用的模块。 如果每次都把这些模块的代码复制粘贴到不同的页面,那简直是噩梦。 get_template_part()
就解决了这个问题,它允许你把这些模块分别写在不同的文件里,然后在需要的地方调用它们。
1.1 基本用法
get_template_part()
的基本用法很简单:
<?php get_template_part( 'template-parts/content', 'page' ); ?>
这行代码的意思是:加载 template-parts/content-page.php
文件。
- 第一个参数
'template-parts/content'
是模板文件的“slug”,也就是文件名的一部分,用来区分不同的模板部分。 - 第二个参数
'page'
是可选的“name”,用来指定更具体的模板文件。 如果省略第二个参数,那么就只加载第一个参数对应的文件。
1.2 查找顺序
get_template_part()
会按照一定的顺序查找模板文件:
template-parts/content-page.php
template-parts/content.php
也就是说,如果第一个文件存在,就加载它;如果第一个文件不存在,就加载第二个文件。
二、locate_template()
:模板文件查找背后的功臣
get_template_part()
真正干活的是 locate_template()
函数。 locate_template()
负责根据给定的文件名,在主题目录和子主题目录中查找模板文件,并返回找到的文件的完整路径。 如果找不到,就返回空字符串。
2.1 locate_template()
的参数
locate_template()
接受以下参数:
$template_names
(array|string) (Required) 一个包含模板文件名的数组,或者一个单独的模板文件名字符串。$load
(bool) (Optional) 是否加载模板文件。 默认为 false,只返回文件路径。$require_once
(bool) (Optional) 是否使用require_once()
加载模板文件。 默认为 true,防止重复加载。
2.2 源码剖析
现在,让我们深入 locate_template()
的源码,看看它到底是怎么工作的:
function locate_template( $template_names, $load = false, $require_once = true ) {
$located = '';
$template_names = (array) $template_names;
if ( empty( $template_names ) ) {
return $located;
}
$theme_search_paths = apply_filters( 'theme_search_paths', array( 10 => get_stylesheet_directory(), 20 => get_template_directory() ) );
ksort( $theme_search_paths );
$theme_search_paths = array_unique( $theme_search_paths );
foreach ( $template_names as $template_name ) {
if ( ! $template_name ) {
continue;
}
foreach ( $theme_search_paths as $dir ) {
if ( file_exists( $dir . '/' . $template_name ) ) {
$located = $dir . '/' . $template_name;
break 2;
}
}
}
if ( $load && '' !== $located ) {
load_template( $located, $require_once );
}
return $located;
}
2.3 源码解读
-
参数处理:
- 首先,将
$template_names
转换为数组,方便后续处理。 - 如果
$template_names
为空,直接返回空字符串。
- 首先,将
-
构建搜索路径:
theme_search_paths
是一个数组,包含了主题和子主题的目录。 默认情况下,它包含两个元素:get_stylesheet_directory()
:子主题的目录(如果存在子主题)。get_template_directory()
:父主题的目录。
apply_filters( 'theme_search_paths', ... )
:允许开发者通过 filter 修改搜索路径。 这提供了极大的灵活性,可以自定义模板文件的查找位置。ksort($theme_search_paths)
和array_unique($theme_search_paths)
确保搜索路径的顺序是确定的,并且没有重复的路径。ksort
按照键值排序,确保优先级高的路径排在前面。array_unique
删除重复的路径,避免重复搜索。
-
循环查找:
- 外层循环遍历
$template_names
数组,逐个查找模板文件。 - 内层循环遍历
$theme_search_paths
数组,逐个在不同的目录中查找。 file_exists( $dir . '/' . $template_name )
:判断文件是否存在。 如果存在,将文件路径赋值给$located
,并跳出两层循环。
- 外层循环遍历
-
加载模板:
- 如果
$load
为 true,并且找到了模板文件,就调用load_template()
函数加载模板文件。 load_template( $located, $require_once )
:加载模板文件。require_once
参数控制是否使用require_once()
加载,防止重复加载。
- 如果
-
返回值:
- 返回找到的模板文件的完整路径。 如果没有找到,返回空字符串。
三、load_template()
:最终的模板加载
load_template()
函数负责真正加载模板文件。 它的源码很简单:
function load_template( $_template_file, $require_once = true, $args = array() ) {
global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite, $wpdb, $wp_locale, $wp, $l10n, $did_action, $doing_it_wrong, $pagenow;
if ( is_array( $args ) ) {
extract( $args, EXTR_SKIP );
}
if ( $require_once ) {
require_once( $_template_file );
} else {
require( $_template_file );
}
}
3.1 源码解读
-
全局变量:
global ...
:声明了一堆全局变量,使得模板文件中可以访问这些变量。 这些变量包含了 WordPress 的核心数据和功能,比如文章数据、查询对象、数据库连接等等。
-
提取参数:
extract( $args, EXTR_SKIP )
:将$args
数组中的键值对提取为变量。EXTR_SKIP
参数表示如果变量名已经存在,则跳过提取。 这允许在调用load_template()
时传递一些自定义的变量到模板文件中。
-
加载模板文件:
require_once( $_template_file )
或require( $_template_file )
:使用require_once()
或require()
加载模板文件。require_once()
确保文件只被加载一次,防止重复加载。
四、get_template_part()
的完整流程
现在,让我们把 get_template_part()
、locate_template()
和 load_template()
串起来,看看整个流程是怎么样的:
- 调用
get_template_part( $slug, $name )
。 get_template_part()
根据$slug
和$name
构建模板文件名数组。 比如,如果$slug
是'template-parts/content'
,$name
是'page'
,那么模板文件名数组就是['template-parts/content-page.php', 'template-parts/content.php']
。get_template_part()
调用locate_template( $template_names, true )
。locate_template()
在主题目录和子主题目录中查找模板文件。- 如果
locate_template()
找到了模板文件,就返回文件的完整路径;否则,返回空字符串。 - 如果
locate_template()
返回了文件路径,get_template_part()
就什么也不做(因为locate_template()
已经加载了模板文件)。 如果locate_template()
返回了空字符串,get_template_part()
就什么也不做。
五、实例分析
假设你的主题目录是 /wp-content/themes/my-theme/
,并且你的主题中有一个 template-parts/content-page.php
文件。
当你调用 get_template_part( 'template-parts/content', 'page' )
时,会发生以下事情:
get_template_part()
构建模板文件名数组:['template-parts/content-page.php', 'template-parts/content.php']
。get_template_part()
调用locate_template( ['template-parts/content-page.php', 'template-parts/content.php'], true )
。locate_template()
首先在子主题目录中查找template-parts/content-page.php
。 如果没有子主题,就跳过这一步。locate_template()
在父主题目录/wp-content/themes/my-theme/
中查找template-parts/content-page.php
。locate_template()
找到了文件,返回/wp-content/themes/my-theme/template-parts/content-page.php
。locate_template()
因为$load
参数是true
,所以调用load_template( '/wp-content/themes/my-theme/template-parts/content-page.php' )
。load_template()
加载/wp-content/themes/my-theme/template-parts/content-page.php
文件,并将文件内容插入到当前模板中。
六、get_template_part()
的应用场景
get_template_part()
在 WordPress 主题开发中应用非常广泛,主要用于以下场景:
- 模块化主题结构: 将主题的不同部分(比如页眉、页脚、侧边栏、文章列表)分别放在不同的文件中,然后使用
get_template_part()
在需要的地方加载它们。 - 创建可重用的模板片段: 将一些常用的 HTML 代码片段(比如按钮、表单、导航菜单)放在单独的文件中,然后使用
get_template_part()
在不同的页面中重复使用它们。 - 构建灵活的页面布局: 根据不同的条件加载不同的模板片段,从而实现灵活的页面布局。 比如,可以根据文章的类型加载不同的文章模板。
- 子主题定制: 子主题可以通过覆盖父主题的模板片段来实现定制化。 只需要在子主题中创建一个同名的模板文件,就可以覆盖父主题的模板片段。
七、总结
get_template_part()
和 locate_template()
是 WordPress 主题开发中非常重要的函数。 它们实现了主题的模块化,提高了代码的可重用性和可维护性。 通过深入了解它们的源码和工作原理,你可以更好地理解 WordPress 主题的结构,并开发出更加灵活和强大的主题。 记住,灵活运用 theme_search_paths
过滤器,可以扩展模板查找的范围,让你的主题更加强大。 好了,今天的讲座就到这里,希望大家有所收获!下次有机会再见!