各位观众老爷,晚上好!我是今天的主讲人,咱们今天聊聊WordPress主题开发里一个非常实用,甚至可以说不可或缺的函数——get_template_part()
。 这玩意儿就像乐高积木,能让你把主题模板拆成一块块,然后想怎么拼就怎么拼,大大提高代码复用率,让你的主题结构更清晰、更容易维护。
咱们先来个热身,用人话描述一下get_template_part()
的功能:
get_template_part()
:主题模板的模块化利器,它允许你加载并包含指定名称的模板片段文件。
是不是很简单?别急,更精彩的还在后面。
一、get_template_part()
的基本用法
最简单的用法是这样的:
<?php get_template_part( 'template-parts/content', 'page' ); ?>
这行代码会尝试加载以下文件(按优先级从高到低):
template-parts/content-page.php
template-parts/content.php
也就是说,get_template_part()
函数接受两个参数:
$slug
(必需):模板片段的基本名称(例如,template-parts/content
)。$name
(可选):模板片段的额外名称(例如,page
)。
函数会根据这两个参数,按特定的顺序搜索模板文件,找到第一个匹配的文件就加载它。 如果 $name
参数为空,则只会搜索 $slug.php
。
二、为什么要用 get_template_part()
?
说了这么多,你可能要问了:直接 include
或者 require
不香吗? 为啥非要用这个 get_template_part()
?
原因在于:
- 可维护性: 将主题拆分成小的、可重用的模块,更容易理解和修改。
- 可扩展性: 方便子主题覆盖父主题的模板片段。
- 代码复用: 避免重复编写相同的代码。
- 主题结构清晰: 更好地组织主题文件。
举个例子,假设你的主题首页和存档页都需要显示文章列表,文章的显示方式基本相同,只有一些细微的差别。 如果不用 get_template_part()
,你可能需要在 index.php
和 archive.php
里都写一遍文章列表的代码,一旦需要修改,就要改两处地方,简直是噩梦。
如果用 get_template_part()
,你可以把文章列表的代码提取到一个单独的模板片段文件(例如 template-parts/content.php
),然后在 index.php
和 archive.php
里都调用 get_template_part( 'template-parts/content' )
,这样就只需要维护一个文件了。
三、get_template_part()
源码分析
理论讲完了,咱们来扒一扒 get_template_part()
的源码,看看它到底是怎么工作的。 (友情提示:前方代码高能,请系好安全带!)
get_template_part()
函数位于 wp-includes/template.php
文件中。 为了方便大家理解,我把源码简化了一下,去掉了部分不常用的参数和代码:
function get_template_part( $slug, $name = null, $args = array() ) {
/**
* Fires before the specified template part file is loaded.
*
* The dynamic portion of the hook name, `$slug`, refers to the slug
* name for the generic template part.
*
* @since 3.0.0
*
* @param string $slug The slug name for the generic template part.
* @param string|null $name The name of the specialized template part.
*/
do_action( "get_template_part_{$slug}", $slug, $name );
$templates = array();
$name = (string) $name;
if ( '' !== $name ) {
$templates[] = "{$slug}-{$name}.php";
}
$templates[] = "{$slug}.php";
/**
* Filters the list of template filenames to search for when calling `get_template_part()`.
*
* The dynamic portion of the hook name, `$slug`, refers to the slug
* name for the generic template part.
*
* @since 4.0.0
*
* @param string[] $templates List of template filenames to search for.
* @param string $slug Slug of the template.
* @param string|null $name Name of the template.
*/
$templates = apply_filters( "get_template_part_{$slug}", $templates, $slug, $name );
locate_template( $templates, true, false, $args );
}
咱们一行一行地分析:
-
do_action( "get_template_part_{$slug}", $slug, $name );
这是一个 action hook,允许开发者在加载模板片段之前执行一些自定义操作。 例如,你可以根据
$slug
和$name
的值,动态地修改一些全局变量,或者执行一些权限检查。 -
$templates = array();
创建一个空数组,用来存储要搜索的模板文件路径。
-
$name = (string) $name;
将
$name
强制转换为字符串类型。 -
if ( '' !== $name ) { $templates[] = "{$slug}-{$name}.php"; }
如果
$name
不为空,则将{$slug}-{$name}.php
添加到$templates
数组中。 这就是为什么get_template_part( 'template-parts/content', 'page' )
会首先搜索template-parts/content-page.php
的原因。 -
$templates[] = "{$slug}.php";
将
{$slug}.php
添加到$templates
数组中。 这就是为什么get_template_part( 'template-parts/content', 'page' )
在找不到template-parts/content-page.php
时,会搜索template-parts/content.php
的原因。 -
$templates = apply_filters( "get_template_part_{$slug}", $templates, $slug, $name );
这是一个 filter hook,允许开发者修改
$templates
数组。 你可以通过这个 hook,添加、删除或修改要搜索的模板文件路径。 这为主题的定制提供了极大的灵活性。 -
locate_template( $templates, true, false, $args );
这是最关键的一步,它调用了
locate_template()
函数来查找并加载模板文件。$templates
:要搜索的模板文件路径数组。true
:如果找到模板文件,则加载它。false
:不返回模板文件的路径。$args
:传递给模板文件的参数数组。
四、locate_template()
源码分析
locate_template()
函数位于 wp-includes/template.php
文件中,它的作用是在主题目录及其父主题目录中查找指定的模板文件。
function locate_template( $template_names, $load = false, $require_once = true, $args = array() ) {
$located = '';
foreach ( (array) $template_names as $template_name ) {
if ( ! $template_name ) {
continue;
}
if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) {
$located = STYLESHEETPATH . '/' . $template_name;
break;
} elseif ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) {
$located = TEMPLATEPATH . '/' . $template_name;
break;
} elseif ( file_exists( WPINC . '/theme-compat/' . $template_name ) ) {
$located = WPINC . '/theme-compat/' . $template_name;
break;
}
}
if ( $load && '' !== $located ) {
load_template( $located, $require_once, $args );
}
return $located;
}
咱们一行一行地分析:
-
$located = '';
初始化一个空字符串,用来存储找到的模板文件的路径。
-
foreach ( (array) $template_names as $template_name ) { ... }
遍历
$template_names
数组,依次查找每个模板文件。 -
if ( ! $template_name ) { continue; }
如果
$template_name
为空,则跳过本次循环。 -
if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) { ... }
检查当前主题目录中是否存在
$template_name
文件。STYLESHEETPATH
常量指向当前主题的目录。 -
elseif ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) { ... }
如果当前主题目录中不存在
$template_name
文件,则检查父主题目录中是否存在$template_name
文件。TEMPLATEPATH
常量指向父主题的目录。 -
elseif ( file_exists( WPINC . '/theme-compat/' . $template_name ) ) { ... }
如果父主题目录中也不存在
$template_name
文件,则检查 WordPress 核心的theme-compat
目录中是否存在$template_name
文件。 这个目录包含一些默认的模板文件,用于在主题缺少某些必要文件时提供兼容性支持。 -
if ( $load && '' !== $located ) { load_template( $located, $require_once, $args ); }
如果
$load
为true
且找到了模板文件,则调用load_template()
函数来加载模板文件。 -
return $located;
返回找到的模板文件的路径。
五、load_template()
源码分析
load_template()
函数位于 wp-includes/template.php
文件中,它的作用是加载指定的模板文件,并将其中的代码包含到当前文件中。
function load_template( $_template_file, $require_once = true, $args = array() ) {
global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
if ( is_array( $wp_query->query_vars ) ) {
extract( $wp_query->query_vars, EXTR_SKIP );
}
if ( isset( $args ) && is_array( $args ) ) {
extract( $args, EXTR_SKIP );
}
if ( $require_once ) {
require_once( $_template_file );
} else {
require( $_template_file );
}
}
咱们一行一行地分析:
-
global ...
声明一些全局变量,使模板文件可以访问 WordPress 的核心对象和数据。
-
if ( is_array( $wp_query->query_vars ) ) { extract( $wp_query->query_vars, EXTR_SKIP ); }
将
$wp_query->query_vars
数组中的键值对提取为变量。 这使得模板文件可以访问 URL 中的查询参数。 -
if ( isset( $args ) && is_array( $args ) ) { extract( $args, EXTR_SKIP ); }
将
$args
数组中的键值对提取为变量。 这使得模板文件可以访问通过get_template_part()
函数传递的参数。 -
if ( $require_once ) { require_once( $_template_file ); } else { require( $_template_file ); }
根据
$require_once
的值,使用require_once()
或require()
函数来加载模板文件。require_once()
函数只会加载一次模板文件,避免重复加载;require()
函数则每次都会加载模板文件。
六、get_template_part()
的高级用法
除了基本用法之外,get_template_part()
还有一些高级用法,可以让你更灵活地控制模板片段的加载。
-
传递参数:
可以通过
$args
参数,将数据传递给模板片段文件。<?php $args = array( 'title' => 'Hello World!', 'content' => 'This is some content.', ); get_template_part( 'template-parts/content', null, $args ); ?>
然后在
template-parts/content.php
文件中,你可以通过$title
和$content
变量来访问这些数据。<h1><?php echo esc_html( $title ); ?></h1> <p><?php echo esc_html( $content ); ?></p>
-
使用 Filter Hook 修改模板路径:
可以通过
get_template_part_{$slug}
filter hook,动态地修改要搜索的模板文件路径。add_filter( 'get_template_part_template-parts/content', 'my_custom_template_part', 10, 3 ); function my_custom_template_part( $templates, $slug, $name ) { if ( is_page( 'about' ) ) { $templates = array( 'template-parts/content-about.php', 'template-parts/content.php' ); } return $templates; }
这段代码的意思是:当加载
template-parts/content
模板片段时,如果当前页面是 "about" 页面,则优先搜索template-parts/content-about.php
文件。 -
在子主题中覆盖父主题的模板片段:
子主题可以覆盖父主题的模板片段,只需要在子主题中创建与父主题相同路径和名称的模板文件即可。 例如,如果父主题有一个
template-parts/content.php
文件,你可以在子主题中创建一个template-parts/content.php
文件,子主题的这个文件就会覆盖父主题的同名文件。
七、get_template_part()
的使用建议
为了更好地使用 get_template_part()
函数,我给大家一些建议:
-
合理划分模板片段:
将主题拆分成小的、功能单一的模板片段,例如:
template-parts/header.php
:页眉template-parts/footer.php
:页脚template-parts/content.php
:文章内容template-parts/sidebar.php
:侧边栏template-parts/navigation.php
:导航菜单
-
规范命名模板片段:
使用一致的命名规范,例如:
template-parts/content-{$post_type}.php
,这样可以更容易地找到和理解模板片段。 -
善用参数传递:
通过
$args
参数,将数据传递给模板片段,避免在模板片段中直接访问全局变量。 -
利用 Filter Hook 进行定制:
使用
get_template_part_{$slug}
filter hook,动态地修改模板路径,实现更灵活的定制。
八、get_template_part()
的替代方案
虽然 get_template_part()
非常实用,但它并不是唯一的选择。 在某些情况下,你可以考虑使用其他的替代方案:
-
include
或require
:如果不需要子主题覆盖父主题的功能,可以直接使用
include
或require
函数来加载模板文件。 但是,这种方式不如get_template_part()
灵活,可维护性也较差。 -
自定义函数:
可以创建自定义函数来加载模板片段,例如:
function my_get_content_template( $post_type ) { $template = locate_template( array( "template-parts/content-{$post_type}.php", 'template-parts/content.php' ) ); if ( $template ) { include( $template ); } }
这种方式可以更灵活地控制模板片段的加载逻辑,但需要编写更多的代码。
九、总结
get_template_part()
函数是 WordPress 主题开发中一个非常重要的工具,它可以帮助你将主题拆分成小的、可重用的模块,提高代码复用率,让你的主题结构更清晰、更容易维护。 掌握 get_template_part()
的用法,对提高你的 WordPress 主题开发效率非常有帮助。
今天就讲到这里,希望大家有所收获! 下课!