模板引擎的秘密:get_template()
和 get_header()
源码剖析
各位观众,欢迎来到今天的“模板引擎的秘密”讲座!今天,咱们不讲那些花里胡哨的概念,直接扒开 WordPress 源码的裤衩,看看 get_template()
和 get_header()
这两个老伙计到底是怎么加载模板文件的。
准备好了吗?咱们开始!
模板加载的江湖规矩:模板层次结构
在深入源码之前,我们需要先了解 WordPress 模板加载的江湖规矩——模板层次结构。WordPress 会按照一定的顺序查找模板文件,找到第一个就用它。就像古代皇帝选妃,先看家世,再看容貌,一层层筛选。
这套规矩决定了你的主题文件应该如何命名和放置,也决定了 WordPress 会优先使用哪个模板。
举个例子,当请求一个单篇文章页面时,WordPress 会按照以下顺序查找模板文件:
single-{post_type}-{slug}.php
(例如:single-book-the-lord-of-the-rings.php
)single-{post_type}.php
(例如:single-book.php
)single.php
singular.php
index.php
理解了模板层次结构,才能更好地理解 get_template()
和 get_header()
的工作原理。
get_template()
:万能的模板加载器
get_template()
是一个非常重要的函数,几乎所有的模板文件加载都依赖它。它的主要功能是:
- 根据给定的模板名称,查找匹配的模板文件。
- 如果找到,就加载该模板文件。
- 如果没找到,就使用默认的模板文件。
咱们先看看 get_template()
的简化版源码(为了方便讲解,我做了一些简化,省略了一些不常用的参数和条件判断):
function get_template( $template_name, $require_once = true, $args = array() ) {
$template_names = (array) $template_name; // 确保模板名称是数组
$located = locate_template( $template_names, $require_once, false ); // 找到模板文件
if ( $located ) {
load_template( $located, $require_once, $args ); // 加载模板文件
} else {
// 如果没找到模板,可以执行一些默认操作,例如输出错误信息
// 或者加载一个默认的模板
}
}
这个函数的核心在于两行:locate_template()
和 load_template()
。
-
locate_template()
:寻找模板文件locate_template()
函数负责根据给定的模板名称,在主题目录中查找匹配的模板文件。它的源码比较复杂,涉及到主题目录的查找、父主题和子主题的判断等等。咱们也来简化一下
locate_template()
的源码:function locate_template( $template_names, $load = false, $require_once = true ) { $located = false; foreach ( (array) $template_names as $template_name ) { if ( ! $template_name ) { continue; } // 1. 在子主题中查找 if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) { $located = STYLESHEETPATH . '/' . $template_name; break; } // 2. 在父主题中查找 if ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) { $located = TEMPLATEPATH . '/' . $template_name; break; } } if ( $load && '' != $located ) { load_template( $located, $require_once ); } return $located; }
locate_template()
的查找顺序是:- 子主题目录 (STYLESHEETPATH)
- 父主题目录 (TEMPLATEPATH)
如果找到了模板文件,就返回该文件的路径;否则,返回
false
。 -
load_template()
:加载模板文件load_template()
函数负责加载找到的模板文件。它实际上就是使用require_once
或require
语句来包含模板文件。function load_template( $_template_file, $require_once = true, $args = array() ) { global $posts, $post, $wp_did_header, $wp_did_template_redirect, $wp_query, $wp, $wp_rewrite, $wp_the_query; if ( is_array( $args ) ) { extract( $args, EXTR_SKIP ); } if ( $require_once ) { require_once( $_template_file ); } else { require( $_template_file ); } }
注意
extract( $args, EXTR_SKIP )
这行代码。它会将$args
数组中的键值对提取为变量,这样就可以在模板文件中使用这些变量了。
get_template()
的使用场景
get_template()
可以用于加载任何类型的模板文件,例如:
get_template( 'sidebar.php' )
:加载侧边栏模板。get_template( 'content.php' )
:加载文章内容模板。get_template( array( 'content-page.php', 'content.php' ) )
:尝试加载content-page.php
,如果找不到,则加载content.php
。
get_header()
:加载头部模板
get_header()
函数专门用于加载头部模板。它的源码相对简单,但也有一些值得注意的地方。
function get_header( $name = null, $args = array() ) {
/**
* Fires before the header template file is loaded.
*
* @since 2.1.0
*
* @param string|null $name Name of the specific header file to use. Null for the default header.
* @param array $args Additional arguments passed to the header template.
*/
do_action( 'get_header', $name, $args );
$templates = array();
$name = (string) $name;
if ( '' !== $name ) {
$templates[] = "header-{$name}.php";
}
$templates[] = 'header.php';
/**
* Filters the list of header template files to search for.
*
* @since 4.0.0
*
* @param string[] $templates An ordered array of header template files names to search for.
* @param string $name Name of the template to load.
* @param array $args Additional arguments passed to the header template.
*/
$templates = apply_filters( 'header_templates', $templates, $name, $args );
locate_template( $templates, true, $args );
}
get_header()
的工作流程如下:
- 触发
get_header
action hook。 这个钩子允许你在加载头部模板之前执行一些自定义操作。 - 构建模板名称数组。 如果指定了
$name
参数,则会尝试加载header-{$name}.php
;否则,加载header.php
。 - 应用
header_templates
filter hook。 这个钩子允许你修改模板名称数组,例如添加自定义的头部模板。 - 使用
locate_template()
加载模板文件。 这里调用了我们前面讲过的locate_template()
函数,根据模板名称数组查找并加载模板文件。
get_header()
的使用场景
get_header()
主要用于加载头部模板,通常在主题的 index.php
、single.php
、page.php
等文件中使用。
get_header()
:加载默认的header.php
模板。get_header( 'home' )
:加载header-home.php
模板。 这可以用于为首页加载不同的头部。
实例分析:加载文章列表页面的头部
假设我们有一个主题,并且想要在文章列表页面(例如首页或分类页面)加载一个自定义的头部模板。
-
创建
header-blog.php
文件。 在你的主题目录下创建一个名为header-blog.php
的文件,并添加你想要显示的 HTML 代码。<!-- header-blog.php --> <div class="blog-header"> <h1>我的博客</h1> <p>欢迎来到我的博客,这里记录了我的学习和生活。</p> </div>
-
在
index.php
文件中使用get_header()
函数。 在你的index.php
文件中,将get_header()
函数修改为get_header( 'blog' )
。<!DOCTYPE html> <html <?php language_attributes(); ?>> <head> <meta charset="<?php bloginfo( 'charset' ); ?>"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><?php wp_title( '|', true, 'right' ); ?></title> <?php wp_head(); ?> </head> <body <?php body_class(); ?>> <?php get_header( 'blog' ); // 加载 header-blog.php ?> <div class="container"> <!-- 你的文章列表内容 --> </div> <?php get_footer(); ?> <?php wp_footer(); ?> </body> </html>
现在,当你访问文章列表页面时,WordPress 就会加载
header-blog.php
文件,而不是默认的header.php
文件。
灵魂拷问:为什么要用函数?
你可能会问,为什么 WordPress 不直接使用 require_once
或 include
来加载模板文件,而是要封装成 get_template()
和 get_header()
这样的函数呢?
原因有很多,但主要有以下几点:
- 代码复用: 避免在多个文件中重复编写相同的模板加载逻辑。
- 模板层次结构:
get_template()
函数实现了模板层次结构,可以根据不同的条件加载不同的模板文件。 - Hook 机制:
get_template()
和get_header()
函数都使用了 action 和 filter 钩子,允许开发者在模板加载过程中进行自定义操作。 - 可维护性: 将模板加载逻辑封装成函数,可以提高代码的可维护性,方便以后进行修改和扩展。
总结
今天,我们一起剖析了 get_template()
和 get_header()
函数的源码,了解了它们是如何加载模板文件的。
get_template()
是一个通用的模板加载器,可以用于加载任何类型的模板文件。get_header()
专门用于加载头部模板。- 这两个函数都利用了模板层次结构和 Hook 机制,提供了强大的灵活性和可定制性。
希望今天的讲座能够帮助你更好地理解 WordPress 模板引擎的工作原理。下次再见!
附录:常用模板函数速查表
函数名 | 功能 | 示例 |
---|---|---|
get_header() |
加载头部模板。 | get_header(); get_header('home'); |
get_footer() |
加载底部模板。 | get_footer(); get_footer('alternative'); |
get_sidebar() |
加载侧边栏模板。 | get_sidebar(); get_sidebar('primary'); |
get_template() |
加载任何类型的模板文件,支持模板层次结构。 | get_template('content.php'); |
locate_template() |
根据模板名称数组查找模板文件,但不加载。 | $template = locate_template(array('content.php')); |
load_template() |
加载指定的模板文件。通常与 locate_template() 配合使用。 |
load_template($template); |
get_stylesheet_directory() |
获取当前主题的样式表目录(子主题目录)。 | get_stylesheet_directory() . '/images/logo.png'; |
get_template_directory() |
获取当前主题的模板目录(父主题目录)。 | get_template_directory() . '/template-parts/content.php'; |
记住这些函数,你就能像一位真正的 WordPress 大师一样,轻松驾驭模板引擎,打造出令人惊艳的主题!