钩(Hook)是 WordPress 最核心的机制,也是它为什么能被改造出无穷功能的原因。但很多人被「add_action」「add_filter」这些函数名劝退了。
其实这个概念本身很简单。这篇用不用写代码也能懂的方式讲清楚,看完你会明白插件是怎么工作的,以及为什么改 WordPress 不该去改核心文件。
一、一句话理解钩子
WordPress 在执行过程中,会在很多地方「喊一嗓子」:「我现在要输出页面头部了,谁有事要办吗?」
你的代码可以「举手应答」:「我有事,我要在这里加一段统计代码。」
这就是钩子的全部。WordPress 喊的那些点叫做钩子(Hook),你的应答叫做回调函数。
二、两种钩子:Action 和 Filter
这两者的区别是新手最容易混淆的地方,其实一句话就能分清:
- Action(动作):在某个时刻做一件事。不返回值。
- Filter(过滤器):在某个数据被使用前修改它。必须返回值。
Action 的例子
「页面头部输出的时候,我要加一行代码」——这是做事,用 Action。
add_action( 'wp_head', function() {
echo '<!-- 我加的东西 -->';
});
Filter 的例子
「文章标题显示之前,我要给它加个前缀」——这是改数据,用 Filter。
add_filter( 'the_title', function( $title ) {
return '【置顶】' . $title;
});
注意 Filter 必须有 return。这是最常见的错误——写了 Filter 忘了 return,结果标题变空白。
三、钩子的执行顺序:优先级
同一个钩子可以有多个人应答。谁先谁后?由第三个参数决定:
add_action( 'wp_head', 'func_a', 5 ); // 先执行 add_action( 'wp_head', 'func_b', 10 ); // 后执行(默认 10) add_action( 'wp_head', 'func_c', 20 ); // 最后执行
数字小的先执行,默认是 10。
这个机制很重要,因为它决定了你能不能「插队」或者「垫后」。比如你想在某个插件的输出之后再加点东西,就把优先级设大一点。
四、为什么这个设计这么重要
假设没有钩子,你想在页面头部加统计代码,只能:
- 打开 WordPress 核心文件
header.php - 手动插入代码
- 下次 WordPress 更新,你的改动被覆盖
有了钩子:
- 你写个插件或者代码片段
- WordPress 更新完全不影响
- 随时可以停用
这就是「永远不要改 WordPress 核心文件」这条铁律的原因——钩子给你提供了所有你需要的扩展点,改核心没有任何必要。
五、常用的钩子都在哪
知道几个常用钩子,你就能做大部分定制了。
前台输出类
| 钩子 | 触发时机 | 典型用途 |
|---|---|---|
wp_head |
页面 <head> 输出时 | 加统计代码、加 meta 标签 |
wp_footer |
页面底部输出时 | 加客服插件、加脚本 |
wp_enqueue_scripts |
加载 JS/CSS 时 | 正确引入样式和脚本 |
the_content |
文章正文输出前(Filter) | 在正文前后加内容 |
流程类
| 钩子 | 触发时机 |
|---|---|
init |
WordPress 初始化完成 |
template_redirect |
决定用哪个模板之前(做跳转常用) |
wp_loaded |
WordPress 完全加载后 |
save_post |
文章保存时 |
后台类
| 钩子 | 用途 |
|---|---|
admin_menu |
添加后台菜单 |
admin_init |
后台初始化 |
admin_notices |
后台提示信息 |
六、怎么知道某个功能对应哪个钩子
这是实际开发中最高频的问题。三个办法:
1. 查官方文档
WordPress 官方的 Hooks 参考(developer.wordpress.org/reference/hooks)列出了所有钩子。
2. 装 Query Monitor 插件
它有个 Hooks & Actions 面板,能显示当前页面触发的所有 hook 以及挂在上面的函数。排查问题的利器。
3. 搜索源码
在 WordPress 源码里搜 do_action( 或 apply_filters(,能找到所有钩子的定义位置。适合想知道「这个钩子触发时,上下文里有什么变量」的时候。
七、实战:三个常见需求
需求 1:在每篇文章末尾自动加一段版权声明
add_filter( 'the_content', function( $content ) {
if ( is_single() ) {
$content .= '<p class="copyright">本文为原创,转载请注明出处</p>';
}
return $content;
});
is_single() 判断是不是文章页,避免在列表页也加上。
需求 2:把 Google Analytics 代码加到头部
add_action( 'wp_head', function() {
?>
<!-- Global site tag -->
<script async src="https://www.googletagmanager.com/gtag/js?id=你的ID"></script>
<?php
});
其实这种需求用专门的插件(或者主题的集成设置)更好,这里只是演示原理。
需求 3:登录后跳转到指定页面
add_filter( 'login_redirect', function( $redirect_to, $request, $user ) {
return home_url( '/my-account/' );
}, 10, 3 );
注意最后两个参数:10 是优先级,3 是接受的参数个数。如果你要用回调函数里的第 2、3 个参数,必须声明参数个数,否则拿不到。
这是另一个高频错误:写了三个参数但没声明 3,结果后两个是 null。
八、移除别人的钩子
有时候你不想加东西,而是想去掉某个插件或主题加的东西。
remove_action( 'wp_head', '某个插件的函数名', 10 );
关键:优先级必须和添加时一致。如果对方用 add_action( 'wp_head', 'foo', 20 ),你必须 remove_action( 'wp_head', 'foo', 20 ),写 10 是去不掉的。
另一个坑:remove_action 必须在对方 add_action 之后执行。如果插件还没加载,你去 remove 是无效的。通常要包一层:
add_action( 'wp_loaded', function() {
remove_action( 'wp_head', 'foo', 20 );
});
九、理解了钩子之后,你看待插件的眼光会变
以后装任何一个插件,你都可以理解为:它只是往 WordPress 的各个钩子上挂了一堆函数。
这也解释了几个现象:
- 为什么插件装多了会慢 —— 钩子上的函数越来越多,每个请求都要执行更多代码
- 为什么插件之间会冲突 —— 两个插件改同一个钩子上的同一份数据,后执行的覆盖先执行的
- 为什么禁用插件能排查问题 —— 它的函数不再挂上去,影响就消失了
最后
钩子这个概念,理解它花不了十分钟,但它是从「只会装插件」到「能自己改」的分界线。
你不需要会写复杂代码。只要知道「wp_head 是在头部输出」「the_content 是正文内容」,就能做很多实用的定制——比如在每篇文章末尾加一句引导语,比如在页面底部加一个转化入口。
而这些,正是让一个独立站从「展示页面」变成「获客工具」的关键。