嘿,各位代码界的探险家们,欢迎来到今天的WordPress源码解析讲座!今天,我们要像剥洋葱一样,一层一层地扒开 get_footer()
这个函数,看看它到底是怎么把网站的footer加载出来,并且顺便召唤出 wp_footer()
这个神奇的钩子。
准备好了吗?让我们开始吧!
一、get_footer()
函数:你的网站 Footer 的召唤师
首先,我们要找到这个“召唤师”在哪里。get_footer()
函数通常位于 WordPress 主题的各种模板文件中,比如 index.php
、single.php
、page.php
等等。它的作用很简单,就是告诉 WordPress:“嘿,是时候把 footer 显示出来了!”
让我们看看 get_footer()
函数的源码(位于 wp-includes/template.php
文件中):
function get_footer( $name = null, $args = array() ) {
/**
* Fires before the footer template is loaded.
*
* @since 2.1.0
*
* @param string|null $name Slug of the footer to load.
*/
do_action( 'get_footer', $name );
$templates = array();
$name = (string) $name;
if ( '' !== $name ) {
$templates[] = "footer-{$name}.php";
}
$templates[] = 'footer.php';
locate_template( $templates, true, false, $args );
}
是不是感觉有点眼花缭乱?别担心,让我们一步一步地解读它:
-
do_action( 'get_footer', $name );
:- 这是个钩子!WordPress 的钩子就像一个预留的“插槽”,允许其他插件或主题在某个特定时刻插入自己的代码。
do_action()
函数的作用就是触发这个钩子。 'get_footer'
是钩子的名称,意味着在 footer 模板加载之前,会触发这个钩子。$name
是传递给钩子的参数,它允许你指定一个特定的 footer 名称(稍后会解释)。
简单来说,这行代码的作用是:“在加载 footer 之前,先通知一下大家,看看有没有人想做点什么。”
- 这是个钩子!WordPress 的钩子就像一个预留的“插槽”,允许其他插件或主题在某个特定时刻插入自己的代码。
-
$templates = array();
:- 这行代码创建了一个名为
$templates
的数组,用于存储可能的 footer 模板文件名。
- 这行代码创建了一个名为
-
$name = (string) $name;
:- 这行代码将
$name
变量强制转换为字符串类型,以确保后续操作的类型一致性。
- 这行代码将
-
if ( '' !== $name ) { $templates[] = "footer-{$name}.php"; }
:- 这部分是关键。如果我们在调用
get_footer()
函数时传递了一个$name
参数(例如,get_footer( 'special' )
),那么这行代码就会创建一个名为footer-special.php
的模板文件名,并将其添加到$templates
数组中。 - 这样做的好处是,我们可以根据不同的页面或条件加载不同的 footer 模板。
- 这部分是关键。如果我们在调用
-
$templates[] = 'footer.php';
:- 这行代码将
footer.php
添加到$templates
数组中。footer.php
是默认的 footer 模板文件。 - 即使我们指定了
$name
参数,footer.php
仍然会被添加到$templates
数组的末尾,作为备选方案。
- 这行代码将
-
locate_template( $templates, true, false, $args );
:- 这行代码是真正的“寻宝猎人”。它使用
locate_template()
函数在主题目录中查找$templates
数组中列出的模板文件。 $templates
:要查找的模板文件名数组。true
:如果找到模板文件,则立即加载它。false
:如果找到模板文件,则不返回文件路径。$args
:传递给被加载模板的参数数组(WordPress 5.5 新增)。
locate_template()
函数会按照$templates
数组中模板文件的顺序进行查找,直到找到第一个匹配的文件为止。如果找到了匹配的文件,它会立即加载该文件,并停止查找。如果$templates
数组中的所有文件都没有找到,那么就不会加载任何 footer 模板。 - 这行代码是真正的“寻宝猎人”。它使用
总结一下:
get_footer()
函数的作用是:
- 触发
'get_footer'
钩子。 - 根据
$name
参数创建一个或多个可能的 footer 模板文件名。 - 使用
locate_template()
函数在主题目录中查找这些模板文件,并加载找到的第一个匹配文件。
二、locate_template()
函数:模板文件寻宝大师
locate_template()
函数在 WordPress 中扮演着非常重要的角色,它负责在主题目录中查找模板文件。让我们深入了解一下它的工作原理(位于 wp-includes/template.php
文件中):
function locate_template( $template_names, $load = false, $require_once = true, $args = array() ) {
$located = false;
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;
}
}
if ( ( $load ) && '' !== $located ) {
load_template( $located, $require_once, $args );
}
return $located;
}
让我们逐行分析:
-
$located = false;
:- 初始化一个名为
$located
的变量,用于存储找到的模板文件的路径。初始值为false
,表示尚未找到任何模板文件。
- 初始化一个名为
-
foreach ( (array) $template_names as $template_name ) { ... }
:- 遍历
$template_names
数组,该数组包含要查找的模板文件名。 (array) $template_names
将$template_names
强制转换为数组类型,以确保它可以被foreach
循环遍历。
- 遍历
-
if ( ! $template_name ) { continue; }
:- 如果
$template_name
为空,则跳过当前循环迭代,继续处理下一个模板文件名。
- 如果
-
if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) { ... }
:- 检查当前模板文件名是否存在于当前主题的样式表目录(子主题目录)中。
STYLESHEETPATH
是一个常量,表示当前主题的样式表目录的路径。file_exists()
函数检查指定的文件是否存在。- 如果文件存在,则将
$located
设置为该文件的完整路径,并使用break
语句退出循环。
-
elseif ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) { ... }
:- 如果当前模板文件名不存在于子主题目录中,则检查它是否存在于父主题目录中。
TEMPLATEPATH
是一个常量,表示父主题目录的路径。- 如果文件存在,则将
$located
设置为该文件的完整路径,并使用break
语句退出循环。
-
if ( ( $load ) && '' !== $located ) { load_template( $located, $require_once, $args ); }
:- 如果
$load
参数为true
并且$located
变量不为空(表示找到了模板文件),则使用load_template()
函数加载该模板文件。 $require_once
参数指定是否使用require_once()
函数加载模板文件。如果为true
,则只加载一次该文件,以避免重复加载。$args
参数是一个关联数组,包含要传递给被加载模板的变量。
- 如果
-
return $located;
:- 返回找到的模板文件的路径。如果没有找到任何模板文件,则返回
false
。
- 返回找到的模板文件的路径。如果没有找到任何模板文件,则返回
总结一下:
locate_template()
函数的作用是:
- 遍历模板文件名数组,按照以下顺序查找模板文件:
- 当前主题的样式表目录(子主题目录)。
- 父主题目录。
- 如果找到了匹配的模板文件,则将其路径存储在
$located
变量中,并退出循环。 - 如果
$load
参数为true
,则使用load_template()
函数加载找到的模板文件。 - 返回找到的模板文件的路径。
三、load_template()
函数:模板文件加载器
现在,我们来看看 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_locale, $wp_admin_bar;
/**
* Fires before the specified template is loaded.
*
* @since 1.5.0
*
* @param string $_template_file The path to the template to be loaded.
*/
do_action( 'template_redirect', $_template_file );
if ( is_array( $args ) ) {
extract( $args, EXTR_SKIP );
}
if ( $require_once ) {
require_once( $_template_file );
} else {
require( $_template_file );
}
}
让我们逐行分析:
-
global $posts, $post, $wp_did_template_redirect, $wp_query, $wp, $wp_object_cache, $wp_locale, $wp_admin_bar;
:- 这行代码声明了一些全局变量,以便在加载的模板文件中可以使用这些变量。
- 这些变量包含了 WordPress 的核心数据和功能,例如文章、查询、全局 WordPress 对象等等。
-
do_action( 'template_redirect', $_template_file );
:- 这是一个钩子!它在模板文件加载之前触发
'template_redirect'
钩子。 $_template_file
是传递给钩子的参数,它包含了要加载的模板文件的路径。
- 这是一个钩子!它在模板文件加载之前触发
-
if ( is_array( $args ) ) { extract( $args, EXTR_SKIP ); }
:- 如果
$args
参数是一个数组,则使用extract()
函数将数组中的键值对提取为变量。 EXTR_SKIP
参数告诉extract()
函数,如果变量名已经存在,则跳过提取。- 这样做的好处是,我们可以将一些变量传递给加载的模板文件,并在模板文件中直接使用这些变量。
- 如果
-
if ( $require_once ) { require_once( $_template_file ); } else { require( $_template_file ); }
:- 这行代码使用
require_once()
或require()
函数加载模板文件。 require_once()
函数只加载一次文件,以避免重复加载。require()
函数每次都会加载文件,即使它已经被加载过。$require_once
参数决定使用哪个函数。
- 这行代码使用
总结一下:
load_template()
函数的作用是:
- 声明一些全局变量,以便在加载的模板文件中可以使用这些变量。
- 触发
'template_redirect'
钩子。 - 如果
$args
参数是一个数组,则将数组中的键值对提取为变量。 - 使用
require_once()
或require()
函数加载模板文件。
四、wp_footer()
函数:Footer 的收尾工作
现在,我们终于来到了 wp_footer()
函数。这个函数通常位于 footer.php
文件的末尾,它的作用是在 footer 之后执行一些额外的操作,例如加载 JavaScript 脚本、输出 WordPress 统计信息等等。
让我们看看 wp_footer()
函数的源码(位于 wp-includes/general-template.php
文件中):
function wp_footer() {
/**
* Prints scripts or data before the closing body tag.
*
* @since 0.9.0
*/
do_action( 'wp_footer' );
}
是不是很简单?wp_footer()
函数只有一个作用:触发 'wp_footer'
钩子。
这个钩子允许插件和主题在 footer 之后插入自己的代码,例如 JavaScript 脚本、统计代码等等。
为什么要在 footer 之后加载 JavaScript 脚本?
将 JavaScript 脚本放在 footer 之后加载可以提高页面的加载速度。当浏览器解析 HTML 代码时,如果遇到 <script>
标签,它会暂停解析 HTML 代码,先下载并执行 JavaScript 脚本,然后再继续解析 HTML 代码。如果 JavaScript 脚本位于 <head>
标签中,那么浏览器需要等待所有 JavaScript 脚本加载并执行完毕后才能开始渲染页面,这会导致页面加载速度变慢。
将 JavaScript 脚本放在 footer 之后加载可以避免这个问题。浏览器可以先渲染页面,然后再加载 JavaScript 脚本。这样可以提高页面的加载速度,改善用户体验。
五、get_footer()
和 wp_footer()
的协作
现在,让我们把 get_footer()
和 wp_footer()
函数放在一起,看看它们是如何协作的:
- 在模板文件中调用
get_footer()
函数。 get_footer()
函数触发'get_footer'
钩子。get_footer()
函数根据$name
参数创建一个或多个可能的 footer 模板文件名。get_footer()
函数使用locate_template()
函数在主题目录中查找这些模板文件,并加载找到的第一个匹配文件。locate_template()
函数使用load_template()
函数加载模板文件。load_template()
函数触发'template_redirect'
钩子。footer.php
文件被加载。- 在
footer.php
文件的末尾调用wp_footer()
函数。 wp_footer()
函数触发'wp_footer'
钩子。
总结:
get_footer()
函数负责加载 footer 模板文件,而 wp_footer()
函数负责在 footer 之后执行一些额外的操作。这两个函数通过钩子机制协作,允许插件和主题在 footer 的加载过程中插入自己的代码。
六、一个简单的例子
假设我们想在 footer 中添加一个自定义的 JavaScript 脚本。我们可以这样做:
-
创建一个名为
footer.php
的文件,并将其放置在主题目录中。 -
在
footer.php
文件的末尾添加以下代码:<?php wp_footer(); ?> <script> console.log("Hello from footer!"); </script> </body> </html>
-
在模板文件中调用
get_footer()
函数:<?php get_footer(); ?>
当 WordPress 加载页面时,它会加载 footer.php
文件,并执行 wp_footer()
函数。wp_footer()
函数会触发 'wp_footer'
钩子,然后我们的 JavaScript 脚本会被添加到页面中。
七、进阶技巧:使用 $name
参数加载不同的 Footer
get_footer()
函数的 $name
参数允许我们根据不同的页面或条件加载不同的 footer 模板。例如,我们可以创建一个名为 footer-special.php
的文件,并在特定页面上加载它:
- 创建一个名为
footer-special.php
的文件,并将其放置在主题目录中。 -
在需要加载
footer-special.php
的页面上,调用get_footer( 'special' )
函数:<?php get_footer( 'special' ); ?>
当 WordPress 加载该页面时,它会首先查找 footer-special.php
文件。如果找到了该文件,它会加载该文件。如果没有找到该文件,它会加载默认的 footer.php
文件。
八、最后的忠告:小心陷阱!
- 确保你的
footer.php
文件存在! 这是最常见的错误。 - 不要忘记调用
wp_footer()
函数! 否则,你的 JavaScript 脚本可能无法正常加载。 - 注意子主题和父主题的优先级! 如果子主题中存在
footer.php
文件,那么父主题中的footer.php
文件将被忽略。 - 合理使用钩子! 不要过度使用钩子,否则可能会导致代码混乱。
好了,今天的讲座就到这里。希望通过这次源码解析,大家对 get_footer()
函数有了更深入的了解。记住,理解代码的最好方法就是阅读它、修改它、运行它!祝大家编程愉快!下次再见!