各位观众老爷,晚上好!我是今天的主讲人,咱们今天聊聊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.phptemplate-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 主题开发效率非常有帮助。
今天就讲到这里,希望大家有所收获! 下课!