大家好!今天咱们来聊聊WordPress里一对儿好基友,do_action()
和 apply_filters()
。 这俩家伙,一个负责“发布消息”,一个负责“改头换面”,在WordPress插件开发中那是相当的重要。 搞明白它们的区别和用法,你的WordPress技能就能更上一层楼。
第一节:Action(动作)——“广播站”的那些事儿
想象一下,do_action()
就是个大型广播站,它会发出各种“广播”,告诉大家现在发生了什么事。 比如说,“文章发布了!”,“主题初始化完成了!” 等等。 插件们就像是收音机,可以选择接收自己感兴趣的“广播”。 听到广播后,插件可以执行相应的操作,比如发送邮件,更新数据库,或者做其他任何事情。
1.1 do_action()
的基本用法
do_action()
的基本语法是这样的:
do_action( string $tag, mixed ...$arg );
$tag
: 广播的“频道名称”,也就是钩子的名称。 这很重要,插件就是通过这个频道来“收听”广播的。$arg
: 广播的内容,可以是一个或多个参数,传递给监听这个动作的函数。
举个例子,WordPress在文章发布后会执行 do_action('publish_post', $post_id, $post)
。
do_action( 'publish_post', $post_id, $post );
这里,publish_post
就是广播的频道名称, $post_id
是文章的ID,$post
是文章对象。
1.2 插件如何“收听” Action
插件使用 add_action()
函数来“收听”特定的广播频道。
add_action( string $tag, callable $function_to_add, int $priority = 10, int $accepted_args = 1 );
$tag
: 要收听的广播频道名称。$function_to_add
: 当听到广播后,要执行的函数。$priority
: 优先级,数字越小,优先级越高,越先执行。$accepted_args
: 你的函数希望接收到的参数个数。
例如,如果你想在文章发布后发送邮件,可以这样做:
function my_awesome_function( $post_id, $post ) {
// 发送邮件的代码
wp_mail( '[email protected]', 'New Post Published', 'Post ID: ' . $post_id . ', Title: ' . $post->post_title );
}
add_action( 'publish_post', 'my_awesome_function', 10, 2 );
这段代码的意思是:当 publish_post
广播响起时,执行 my_awesome_function
函数,并且接收两个参数($post_id
和 $post
)。
1.3 do_action()
的源码分析(简化版)
虽然WordPress的源码很复杂,但 do_action()
的核心逻辑其实很简单:
function do_action( $tag, ...$args ) {
global $wp_filter, $wp_actions, $wp_current_filter;
if ( ! isset( $wp_filter[ $tag ] ) ) {
return; // 如果没有插件监听这个频道,就直接返回
}
$wp_current_filter[] = $tag; // 记录当前正在执行的 action
$args = func_get_args(); // 获取所有参数
array_shift( $args ); // 移除第一个参数($tag)
foreach ( $wp_filter[ $tag ] as $priority => $functions ) { // 遍历所有监听这个频道的函数(按优先级排序)
foreach ( $functions as $function ) {
call_user_func_array( $function['function'], $args ); // 执行函数
}
}
array_pop( $wp_current_filter ); // 移除当前正在执行的 action
}
简单来说,do_action()
的工作就是:
- 检查是否有插件监听这个频道。
- 如果有,就按优先级顺序执行所有监听函数,并将参数传递给这些函数。
- 如果没有,就什么也不做。
1.4 Action 的特点总结
特性 | 描述 |
---|---|
目的 | 触发事件,通知插件执行某些操作。 |
返回值 | 无返回值。 Action 主要用于执行操作,而不是修改数据。 |
作用 | 允许插件在特定时刻执行自定义代码,例如发送邮件,更新统计数据,缓存清理等等。 |
监听方式 | 使用 add_action() 函数来注册监听函数。 |
常见用途 | 在文章发布、主题初始化、用户登录等事件发生时,执行自定义操作。 |
源码核心 | 遍历监听函数,按优先级执行。 |
比喻 | 大型广播站,发布各种事件广播,插件可以选择收听。 |
第二节:Filter(过滤器)——“美容院”的那些魔法
现在,我们来看看 apply_filters()
。 你可以把 apply_filters()
想象成一家美容院。它接收一个值(比如一篇文章的内容),然后让各种“美容师”(插件)对这个值进行修改、加工,最后返回修改后的值。
2.1 apply_filters()
的基本用法
apply_filters()
的基本语法是这样的:
apply_filters( string $tag, mixed $value, mixed ...$arg );
$tag
: 过滤器的名称,也就是“美容项目”的名称。$value
: 要过滤的值,也就是要“美容”的对象。$arg
: 可选的额外参数,传递给过滤函数。
举个例子,WordPress在显示文章内容之前会执行 apply_filters('the_content', $content)
。
$content = apply_filters( 'the_content', $content );
这里,the_content
是过滤器的名称,$content
是文章的内容。
2.2 插件如何“参与美容”
插件使用 add_filter()
函数来注册一个过滤函数。
add_filter( string $tag, callable $function_to_add, int $priority = 10, int $accepted_args = 1 );
参数和 add_action()
类似,只是作用略有不同。 $accepted_args
表示你的函数希望接收到的参数个数,其中第一个参数必须是要过滤的值。
例如,如果你想在文章内容后面添加一个版权声明,可以这样做:
function my_awesome_filter( $content ) {
$copyright = '<p>Copyright 2023. All rights reserved.</p>';
return $content . $copyright;
}
add_filter( 'the_content', 'my_awesome_filter' );
这段代码的意思是:当 the_content
过滤器被调用时,执行 my_awesome_filter
函数,并将文章内容作为参数传递给它。 my_awesome_filter
函数会在文章内容后面添加版权声明,并返回修改后的内容。
2.3 apply_filters()
的源码分析(简化版)
apply_filters()
的核心逻辑如下:
function apply_filters( $tag, $value, ...$args ) {
global $wp_filter, $wp_current_filter, $wp_merged_filters;
if ( ! isset( $wp_filter[ $tag ] ) ) {
return $value; // 如果没有插件注册过滤器,就直接返回原始值
}
if ( ! isset( $wp_merged_filters[ $tag ] ) ) {
ksort( $wp_filter[ $tag ] ); // 按优先级排序
$wp_merged_filters[ $tag ] = true;
}
$wp_current_filter[] = $tag;
$args = func_get_args(); // 获取所有参数
// 确保第一个参数是要过滤的值
$hook_args = array_slice( $args, 1 ); // 从第二个参数开始,提取所有参数
foreach ( $wp_filter[ $tag ] as $priority => $functions ) {
foreach ( $functions as $function ) {
$args[1] = $value; // 始终确保第二个参数是要过滤的值
$result = call_user_func_array( $function['function'], $hook_args );
if ( ! is_null( $result ) ) {
$value = $result; // 用过滤后的值更新 $value
}
}
}
array_pop( $wp_current_filter );
return $value; // 返回最终过滤后的值
}
简单来说,apply_filters()
的工作就是:
- 检查是否有插件注册了过滤器。
- 如果没有,就直接返回原始值。
- 如果有,就按优先级顺序执行所有过滤函数,并将原始值和额外参数传递给这些函数。
- 每个过滤函数都应该返回修改后的值,
apply_filters()
会用这个值更新$value
变量。 - 最后,
apply_filters()
返回最终过滤后的值。
2.4 Filter 的特点总结
特性 | 描述 |
---|---|
目的 | 修改数据,允许插件对数据进行加工、处理。 |
返回值 | 必须返回修改后的值。 |
作用 | 允许插件修改文章内容、标题、评论、URL 等等。 |
监听方式 | 使用 add_filter() 函数来注册过滤函数。 |
常见用途 | 在文章显示、URL生成、评论处理等过程中,修改数据。 |
源码核心 | 遍历过滤函数,按优先级执行,并用每个函数返回的值更新原始值。 |
比喻 | 美容院,接收一个值,让各种“美容师”对这个值进行修改,最后返回修改后的值。 |
第三节:Action vs Filter – 终极PK!
现在,我们来总结一下 do_action()
和 apply_filters()
的区别:
特性 | do_action() |
apply_filters() |
---|---|---|
目的 | 触发事件,通知插件执行操作。 | 修改数据,允许插件对数据进行加工。 |
返回值 | 无返回值。 | 必须返回修改后的值。 |
作用 | 允许插件在特定时刻执行自定义代码。 | 允许插件修改数据,例如文章内容、标题等。 |
使用场景 | 当某个事件发生时,需要通知插件执行某些操作。 | 当需要对某个数据进行修改时。 |
比喻 | 广播站 | 美容院 |
重要性 | 像一个大喇叭,告诉大家发生了什么。 | 像一个魔术棒,可以改变事物的形态。 |
3.1 一道练习题
假设你想要开发一个插件,实现以下功能:
- 在文章发布后,发送一条推特。
- 在文章标题后面添加一个“New!” 标签。
你应该如何使用 do_action()
和 apply_filters()
?
答案:
-
发送推特: 使用
do_action()
。 你可以在publish_post
action 中注册一个函数,这个函数负责发送推特。function my_tweet_function( $post_id, $post ) { // 发送推特的代码 // 这里需要调用 Twitter API $tweet_text = $post->post_title . ' - ' . get_permalink( $post_id ); // ... 发送推特的代码 ... } add_action( 'publish_post', 'my_tweet_function', 10, 2 );
-
添加 "New!" 标签: 使用
apply_filters()
。 你可以在the_title
filter 中注册一个函数,这个函数负责在文章标题后面添加 "New!" 标签。function my_new_title_filter( $title ) { return $title . ' <span class="new-label">New!</span>'; } add_filter( 'the_title', 'my_new_title_filter' );
第四节:进阶技巧:优先级和参数
4.1 优先级的重要性
add_action()
和 add_filter()
都有一个 $priority
参数,它决定了插件执行的顺序。 优先级数值越小,执行顺序越靠前。 默认优先级是 10。
例如,如果你有两个插件都监听了 the_content
过滤器:
- 插件 A 的优先级是 5。
- 插件 B 的优先级是 15。
那么,插件 A 会在插件 B 之前执行。
合理设置优先级可以避免插件之间的冲突,保证插件的正常运行。
4.2 如何传递参数
do_action()
和 apply_filters()
都可以传递多个参数。 插件可以通过 $accepted_args
参数来指定希望接收到的参数个数。
例如,如果你的 action 或者 filter 传递了三个参数:
do_action( 'my_custom_action', $arg1, $arg2, $arg3 );
apply_filters( 'my_custom_filter', $value, $arg2, $arg3 );
你的插件应该这样注册:
function my_custom_function( $arg1, $arg2, $arg3 ) {
// ...
}
add_action( 'my_custom_action', 'my_custom_function', 10, 3 );
function my_custom_filter( $value, $arg2, $arg3 ) {
// ...
return $value;
}
add_filter( 'my_custom_filter', 'my_custom_filter', 10, 3 );
注意:在 apply_filters()
中,第一个参数始终是要过滤的值。
第五节:总结与实践
今天,我们深入探讨了 do_action()
和 apply_filters()
的区别和用法。 记住,do_action()
用于触发事件,apply_filters()
用于修改数据。 掌握了它们,你就掌握了 WordPress 插件开发的精髓。
为了巩固学习,建议你尝试开发一些简单的 WordPress 插件,例如:
- 一个在文章发布后发送邮件的插件。
- 一个在文章内容后面添加广告的插件。
- 一个修改文章标题样式的插件。
通过实践,你会更深入地理解 do_action()
和 apply_filters()
的强大之处。
祝大家学习愉快! 下课!