
类型:CMS系统
简介:一款开源的内容管理系统(CMS),用于构建和管理网站。
在前篇《WordPress插件开发入门》中我们简单提过“钩子”这个概念。但很多刚接触插件开发的朋友可能还会疑惑:钩子到底是什么?在开发过程中它起到什么作用?具体又该怎么用呢?今天咱们就带着这些问题,一步步把钩子的用法讲明白。
一、钩子是什么
钩子(Hooks)在WordPress中是一种是用一段代码添加/修改另外一段代码的方式,也是用来开发WordPress插件和主题的重要手段之一。WordPress内核提供了很多钩子,其中Action和Filter是两个最常见的:
1、Action(动作钩子):能在某个函数执行到特定时间点时,帮你加一些自定义操作。比如想在文章末尾自动加一句版权信息,就可以用Action钩子;
2、Filter(过滤钩子):主要用来修改数据,并且会把修改后的数据返回。比如想把文章标题里的某个关键词替换掉,就适合用Filter钩子。
使用钩子时一般需要先编写一个自定义函数作为钩子的回调函数,然后使用add_action或add_filter函数将我们的回调函数挂载到指定的Action或Filter上。
二、Action钩子
1、添加Action
先写回调函数,再把它挂到钩子上。这里要用到add_action()函数,至少要传两个参数:
$tag:你要挂的钩子名称;
$function_to_add:回调函数名称。
下面的例子在init钩子执行时运行:
function wporg_custom() {
// 执行某些操作
}
add_action('init', 'wporg_custom');
2、Action其他参数
add_action()可以传两个额外参数,帮你更灵活地控制回调函数:
(1)优先级:如果一个钩子上挂了多个回调函数,优先级就决定了它们的执行顺序。优先级是整数,默认是10,数字越小,执行越早。
例如,下面的回调函数全部挂载到了init钩子上面,但他们有不同的优先级。
add_action('init', 'run_me_early', 9);
add_action('init', 'run_me_normal'); // 如果没有指定优先级,默认为 10
add_action('init', 'run_me_late', 11);
钩子触发时,会先执行run_me_early()、run_me_normal(),最后执行run_me_late()。
(2)参数个数
有些钩子会自带参数,比如WordPress保存文章时触发的‘save_post‘钩子,会传两个参数——文章ID和文章对象。
do_action('save_post', $post->ID, $post);
在回调函数中使用钩子提供的参数:
function wporg_custom($post_id, $post){
// 执行某些操作
}
例如需要在WordPress的前端文章查询中修改获取搜索结果的查询,可以使用pre_get_posts钩子。
function wporg_search($query) {
if (!is_admin() && $query->is_main_query() && $query->is_search) {
$query->set('post_type', ['post', 'movie']);
}
}
add_action('pre_get_posts', 'wporg_search');
三、Filter钩子
Filter是钩子的另一类,和Action不同的是Filter主要用来修改数据,而且必须把修改后的数据返回,不能有影响全局变量或直接输出内容的操作。
1、添加Filter
添加Filter的步骤和Action类似,先写回调函数,再用add_filter()挂到指定钩子上。add_filter()至少也要传两个参数:$tag(钩子名称)和$function_to_add(回调函数名)。
比如想修改文章标题的显示,在标题前后加文字,就可以用the_title钩子(这个钩子会处理文章标题数据):
function wporg_filter_title($title) {
return '文章:' . $title . '已被修改。';
}
add_filter('the_title', 'wporg_filter_title');
2、Filter其他参数
add_filter()也支持优先级($priority)和参数个数($accepted_args),用法和Action完全一样。
Filter钩子该怎么用?比如想在前端页面的<body>标签上,根据条件加一个自定义CSS类(方便做样式控制),可以用body_class钩子(这个钩子会处理<body>的class属性):
function wporg_css_body_class($classes) {
if (!is_admin()) {
$classes[] = 'wporg-is-awesome';
}
return $classes;
}
add_filter('body_class', 'wporg_css_body_class');
四、自定义钩子
很多开发者会忽略一个重要技巧,在自己的插件里创建自定义钩子,这样其他开发者就能扩展或修改你的插件了。自定义钩子的用法和WordPress核心钩子一样,主要分两步:
1、创建自定义钩子
想创建Action钩子,用do_action()函数,括号里传钩子名称;创建Filter钩子,用apply_filters()函数,除了钩子名称,还要传要处理的数据。
如的插件有输出到浏览器的文本,最好用apply_filters()包一层,这样用户能自己修改输出内容。
2、给自定义钩子挂回调函数
别人想用你的自定义钩子时还是用add_action()(对应自定义Action)或add_filter()(对应自定义Filter),和挂核心钩子的方法一样。
因为所有主题和插件都能创建自定义钩子,所以一定要给钩子名称加唯一前缀,防止和其他插件冲突。
3、自定义钩子示例
示例1:自定义Action
假设你的插件在仪表盘里加了一个设置表单,想让其他开发者能在表单后面加自己的设置项,就可以加一个自定义Action钩子:
function wporg_settings_page_html()
{
?>
Foo: <input id=foo name=foo type=text>
Bar: <input id=bar name=bar type=text>
<?php
do_action('wporg_after_settings_page_html');
}
其他开发者想加自己的设置项,只要把函数挂到这个自定义钩子上就行:
function myprefix_add_settings()
{
?>
New 1: <input id=new_setting name=new_settings type=text>
<?php
}
add_action('wporg_after_settings_page_html', 'myprefix_add_settings');
示例2:自定义Filter
假设你的插件注册了一个自定义文章类型,想让别人能修改这个文章类型的参数(比如是否支持层级),就可以加一个自定义Filter钩子:
function wporg_create_post_type()
{
$post_type_params = [/* ... */];
register_post_type(
'post_type_slug',
apply_filters('wporg_post_type_params', $post_type_params)
);
}
其他开发者想修改参数,只要挂到这个自定义Filter上:
function myprefix_change_post_type_params($post_type_params)
{
$post_type_params['hierarchical'] = true;
return $post_type_params;
}
add_filter('wporg_post_type_params', 'myprefix_change_post_type_params');
五、钩子的高级使用技巧
1、删除已挂载的回调函数
- remove_action():删除Action钩子上的函数;
- remove_filter():删除Filter钩子上的函数。
注意:删除时,传的参数(钩子名称、函数名、优先级)必须和当初add_action/add_filter时完全一样,而且要在函数被挂载之后再执行删除操作。
举个例子,假设需要删除不必要的功能来提高大型主题的性能,就可以这么删:
function my_theme_setup_slider()
{
// ...
}
add_action('template_redirect', 'my_theme_setup_slider', 9);
2、删除某个钩子上的所有回调函数
如果想一次性删除某个钩子上的所有函数,可以用:
- remove_all_actions(‘钩子名称’):删除Action上的所有函数;
- remove_all_filters(‘钩子名称’):删除Filter上的所有函数。
3、判断当前触发的是哪个钩子
如果一个回调函数挂到了多个钩子上,想在函数里区分当前是哪个钩子触发的,可以用:
- current_action():判断当前的Action钩子;
- current_filter():判断当前的Filter钩子(两者用法类似)。
比如:
function wporg_modify_content($content){
switch (current_filter()) {
case 'the_content':
// do something
break;
case 'the_excerpt':
// do something
break;
}
return $content;
}
add_filter('the_content', 'wporg_modify_content');
add_filter('the_excerpt', 'wporg_modify_content');
4、检查钩子是否已经运行过
用did_action(‘钩子名称’)会返回钩子已经运行的次数。比如想让函数只在save_post钩子第一次触发时执行:
function wporg_custom(){
if (did_action('save_post') !== 1) {
return;
}
// ...
}
add_action('save_post', 'wporg_custom');

