嘿,大家好!我是你们今天的WordPress探险向导。今天咱们不聊风花雪月,直接钻到WordPress的心脏里,扒一扒 get_header()
这个小家伙的底裤,看看它到底是怎么把咱们的 header.php
文件加载进来,顺便再扯扯 wp_head()
这个钩子是怎么被触发的。准备好了吗?发车咯!
一、get_header()
:一个简单的函数,一个不简单的任务
get_header()
,顾名思义,就是“获取头部”的意思。在WordPress主题模板中,你几乎可以在每个页面看到它的身影。它负责加载主题目录下的 header.php
文件。简单来说,就是把网站的头部区域,比如 logo、导航菜单、一些元信息等等,都给显示出来。
那么,get_header()
到底做了什么呢?我们来看看它的源码(位于 wp-includes/general-template.php
):
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.
*/
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 filenames.
*
* @since 2.1.0
*
* @param string[] $templates List of header template filenames.
* @param string $name Name of the specific header file to use. Null for the default header.
* @param array $args Additional arguments passed to the header.
*/
$templates = apply_filters( 'header_template_hierarchy', $templates, $name, $args );
locate_template( $templates, true, false, $args );
}
是不是有点眼花缭乱?别怕,咱们一步一步来拆解它。
-
do_action( 'get_header', $name, $args );
: 这是个钩子!在加载任何头部文件之前,WordPress会触发一个名为get_header
的 action hook。 就像是跟其他插件或者主题说:“嘿,我准备加载头部文件了,你们有什么要做的吗?”$name
参数允许指定不同的头部文件(比如header-custom.php
),$args
允许传递一些额外的参数。 -
$templates = array(); ...
: 这里定义了一个$templates
数组,用于存储可能的头部文件名。 WordPress 会尝试按照这个数组的顺序去查找对应的文件。- 如果
$name
不为空(比如get_header('custom')
),那么$templates
数组会先包含header-custom.php
,然后再包含header.php
。 - 如果
$name
为空(默认情况),那么$templates
数组只会包含header.php
。
- 如果
-
$templates = apply_filters( 'header_template_hierarchy', $templates, $name, $args );
: 又是一个钩子!这次是 filter hook。 允许开发者通过header_template_hierarchy
这个过滤器来修改$templates
数组,也就是可以改变 WordPress 查找头部文件的顺序。 这给了我们极大的灵活性,可以根据自己的需求来加载不同的头部文件。 -
locate_template( $templates, true, false, $args );
: 这是整个函数的关键部分。locate_template()
函数会在主题目录下查找$templates
数组中指定的文件。$templates
:要查找的文件名数组。true
:如果找到文件,就直接加载它。false
:不要加载子主题中的模板文件,只加载当前主题的。$args
:传递给模板文件的参数。
二、locate_template()
:寻宝游戏,找到 header.php
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;
}
$template_name = ltrim( $template_name, '/' );
if ( file_exists( get_stylesheet_directory() . '/' . $template_name ) ) {
$located = get_stylesheet_directory() . '/' . $template_name;
break;
}
if ( file_exists( get_template_directory() . '/' . $template_name ) ) {
$located = get_template_directory() . '/' . $template_name;
break;
}
}
if ( $load && '' !== $located ) {
load_template( $located, $require_once, $args );
}
return $located;
}
简单解释一下:
-
遍历
$template_names
数组: 循环查找数组中的每个文件名。 -
检查子主题目录: 首先在当前主题(子主题)的目录下查找文件。如果找到了,就记录下文件路径,然后跳出循环。
-
检查父主题目录: 如果在子主题目录中没有找到文件,就在父主题目录下查找。如果找到了,同样记录下文件路径并跳出循环。
-
load_template( $located, $require_once, $args );
: 如果$load
参数为true
(在get_header()
中就是true
),并且找到了文件,就调用load_template()
函数来加载这个文件。
三、load_template()
:加载模板文件,触发 wp_head()
load_template()
函数负责加载指定的模板文件,并且在加载之前和之后触发一些重要的钩子。 我们来看看它的简化版源码(位于 wp-includes/template.php
):
function load_template( $_template_file, $require_once = true, $args = array() ) {
global $posts, $post, $wp_did_template_redirect, $wp_query, $wp, $wp_object_cache, $_wp_current_template;
do_action( 'template_redirect' );
$_wp_current_template[] = $_template_file;
if ( is_array( $args ) ) {
extract( $args, EXTR_SKIP );
}
if ( $require_once ) {
require_once( $_template_file );
} else {
require( $_template_file );
}
array_pop( $_wp_current_template );
}
关键步骤:
-
do_action( 'template_redirect' );
: 虽然这个钩子和get_header()
没有直接关系,但是它在模板加载之前触发,非常重要。插件和主题可以使用这个钩子来执行一些操作,比如重定向、权限检查等等。 -
extract( $args, EXTR_SKIP );
: 如果传递了$args
参数,那么这个函数会将$args
数组中的键值对提取为变量,方便在模板文件中使用。 -
require_once( $_template_file );
或者require( $_template_file );
: 这才是真正加载模板文件的代码。require_once()
确保文件只会被加载一次,避免重复定义。require()
则允许文件被加载多次。
重点来了!wp_head()
钩子在哪里?
wp_head()
钩子并没有直接出现在 get_header()
、locate_template()
或 load_template()
函数中。 但是,它通常会出现在 header.php
文件中!
打开你的 header.php
文件,你会看到类似这样的代码:
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="profile" href="http://gmpg.org/xfn/11">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<div id="page" class="site">
<a class="skip-link screen-reader-text" href="#content"><?php esc_html_e( 'Skip to content', 'your-theme' ); ?></a>
<header id="masthead" class="site-header" role="banner">
</header><!-- #masthead -->
<div id="content" class="site-content">
wp_head()
函数负责输出一些重要的元信息,比如:
- 网站的标题 (
<title>
) - CSS 样式表 (
<link>
) - JavaScript 脚本 (
<script>
) - 各种 meta 标签
- 等等
wp_head()
的作用:
wp_head()
是一个非常重要的钩子,它允许插件和主题向 <head>
标签中添加内容。 很多插件,比如 SEO 插件、社交分享插件、统计代码插件等等,都会使用 wp_head()
钩子来添加它们需要的代码。
总结一下 get_header()
的工作流程:
我们可以用一张表格来总结一下 get_header()
的工作流程:
步骤 | 描述 | 涉及的函数 | 钩子 |
---|---|---|---|
1 | 触发 get_header 钩子 |
get_header() |
get_header |
2 | 构建模板文件名数组 | get_header() |
无 |
3 | 允许修改模板文件名数组 | get_header() |
header_template_hierarchy |
4 | 查找模板文件 | locate_template() |
无 |
5 | 加载模板文件 | load_template() |
template_redirect |
6 | 执行 header.php 中的代码 |
header.php |
wp_head (通常在 header.php 中调用) |
四、实战演练:自定义头部文件
现在,让我们来做一个小实验,演示如何使用 get_header()
函数加载不同的头部文件。
-
创建
header-custom.php
文件: 在你的主题目录下创建一个名为header-custom.php
的文件。 在这个文件中,你可以添加任何你想要的内容,比如一个不同的 logo,或者一个特殊的导航菜单。<!DOCTYPE html> <html <?php language_attributes(); ?>> <head> <meta charset="<?php bloginfo( 'charset' ); ?>"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="profile" href="http://gmpg.org/xfn/11"> <title>Custom Header</title> <?php wp_head(); ?> </head> <body <?php body_class(); ?>> <div id="page" class="site"> <h1>This is a custom header!</h1>
-
在模板文件中调用
get_header('custom')
: 在你的某个模板文件(比如page.php
)中,将get_header()
修改为get_header('custom')
。<?php get_header('custom'); // 加载 header-custom.php ?> <div id="content" class="site-content"> <?php while ( have_posts() ) : the_post(); the_content(); endwhile; // End of the loop. ?> </div><!-- #content --> <?php get_footer(); ?>
-
刷新页面: 刷新你的页面,你会看到
header-custom.php
中的内容被加载进来了。
五、更高级的玩法:使用 header_template_hierarchy
过滤器
如果你想更灵活地控制头部文件的加载,可以使用 header_template_hierarchy
过滤器。 比如,你可以根据用户的角色来加载不同的头部文件。
add_filter( 'header_template_hierarchy', 'my_custom_header_hierarchy', 10, 3 );
function my_custom_header_hierarchy( $templates, $name, $args ) {
if ( is_user_logged_in() ) {
// 如果用户已登录,则加载 header-logged-in.php
array_unshift( $templates, 'header-logged-in.php' );
} else {
// 如果用户未登录,则加载 header-logged-out.php
array_unshift( $templates, 'header-logged-out.php' );
}
return $templates;
}
这段代码做了什么?
-
注册过滤器: 使用
add_filter()
函数注册一个名为my_custom_header_hierarchy
的过滤器,绑定到header_template_hierarchy
钩子上。 -
my_custom_header_hierarchy
函数: 这个函数接收三个参数:$templates
(模板文件名数组)、$name
(header name)、$args
(参数)。 -
判断用户是否登录: 使用
is_user_logged_in()
函数判断当前用户是否已登录。 -
修改
$templates
数组: 根据用户的登录状态,使用array_unshift()
函数将header-logged-in.php
或header-logged-out.php
添加到$templates
数组的开头。 这样,WordPress 就会优先查找这些文件。
总结
get_header()
函数虽然看起来简单,但它背后涉及了很多重要的机制,包括钩子、模板查找、模板加载等等。 理解 get_header()
的工作原理,可以帮助你更好地控制网站的头部区域,并根据自己的需求进行定制。 同时,它也展示了WordPress强大的扩展性和灵活性。
希望今天的探险之旅对你有所帮助! 下次再见!