WordPress 模板加载的核心函数是load_template
,该函数的作用是加载主题所需的模板文件,并把展示 WordPress 内容需要的全局变量传入这些文件中,用来显示主题。该函数的核心代码如下,注意代码中的 global
, 引入了全局变量,这就是为什么可以直接在主循环中使用全局变量的原因。
function load_template( $_template_file, $require_once = true ) {
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( $s ) ) {
$s = esc_attr( $s );
}
if ( $require_once ) {
require_once( $_template_file );
} else {
require( $_template_file );
}
}
get_template_part 函数 – load_template 的高级封装
该函数使用 locate_template
实现模板文件加载,相当于是 locate_template
的一个封装,看起来比较多余,但其实这在很大程度上方便了开发者来加载模板。该函数通过一个简单的判断,实现了一个容错机制,如果指定了特殊的模板,就加载特殊的模板,如果没有指定,就加载默认的模板。
function get_template_part( $slug, $name = null ) {
/**
* 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.
* @param string $name The name of the specialized template.
*/
do_action( "get_template_part_{$slug}", $slug, $name );
$templates = array();
$name = (string) $name;
if ( '' !== $name )
$templates[] = "{$slug}-{$name}.php";
$templates[] = "{$slug}.php";
locate_template($templates, true, false);
}
get_header 函数 – 支持扩展的模板加载
很多人会想当然,get_header
是 get_template_part
的一个更高级的函数,看了代码,我们会发现,事实并不是这样的,get_header
只是一个hook,返回的是一个名为 $templates
的数组。我们来看一下 get_header
函数的源代码。
function get_header( $name = null ) {
/**
* Fires before the header template file is loaded.
*
* The hook allows a specific header template file to be used in place of the
* default header template file. If your file is called header-new.php,
* you would specify the filename in the hook as get_header( 'new' ).
*
* @since 2.1.0
* @since 2.8.0 $name parameter added.
*
* @param string $name Name of the specific header file to use.
*/
do_action( 'get_header', $name );
$templates = array();
$name = (string) $name;
if ( '' !== $name )
$templates[] = "header-{$name}.php";
$templates[] = 'header.php';
// Backward compat code will be removed in a future release
if ('' == locate_template($templates, true))
load_template( ABSPATH . WPINC . '/theme-compat/header.php');
}
该函数默认包含 header.php 到页面中,并支持传入一个字符串来指定特殊的 header 文件,用来实现在不同的页面显示不同的页面头部信息。如 get_header('home')
,引用的就是 header-home.php。
后面的 get_footer
和 get_sidebar
函数类似,就不多说了。
使用 get_template_part('header')
,get_template_part('header')
同样可以加载模板,看起来也符合 WordPress 的主题规范,但是其实这是不对的,因为缺少了 do_action( 'get_header', $name );
这个hook,会导致一些插件的兼容性问题。
模板加载的优先级及使用方法
get_template_part 函数可以优先加载指定的模板文件,如果指定的模板文件不存在,则再加载默认文件。如:
get_template_part('content', 'product')
上面的函数会优先加载 content-product.php 文件,如果该文件不存在,就加载默认的 content.php 文件。
为什么不直接使用 PHP 的文件包含?
在回答这个问题之前,我们可以从反面思考一个这个问题,为什么不直接能使用 PHP 的文件包含?事实上,使用 PHP 的文件包含也可以达到同样的目的,我就见过一个设计很不错的开发者使用 include
函数来实现模板加载,可是 PHP 的文件包含没有容错机制,不能实现 WordPress 模板加载需要的优先级需求。