当前位置: 首页 > news >正文

wordpress hook机制

稍有接触过WordPress布景或外挂客制修改的朋友,对WordPress的Hook机制应该不陌生,但通常刚接触WordPress Hook的新手,对其运作原理可能会有点混乱或模糊。本文针对WordPress Hook运作大致做个简单的说明,而预设读者是理解基本的PHP function语法及运作,但对WordPress Hook机制不是很明白。

Hook机制里登场的角色

先从「登场角色」的个别说明开始:

WordPress核心

指的是WordPress内建的程式码架构,提供WordPress主要的基本功能。

Hook

也许你早已听说,Hook本身虽是钩子的意思,但直译又有点奇怪,所以一般通常都不直译它,而是直接称它Hook。WordPress的Hook也可以想像成「钩子」,这些「钩子」会埋在WordPress网站中特定几处的程式码中,埋进去时使用的语法,其「标示位置」的意义比较大,没有实质运作的内容。当程式执行到有埋Hook的地方时,它会找出所有对应到自己的Hook Function (也就是所有「钩到」该Hook的hook function),并一一执行。

因此若没有针对此Hook去「加入」要钩上去的Hook Function,执行到此什么也不会做。因此,它等于是WordPress核心预留一个执行的机会给未来想要加入客制功能的开发者。

Hook Function

Hook Function里会有实质运作的内容,即是实作了一些客制功能,可能是存取DB、增加HTML code、执行其他函式…等。我们在Hook Function里写好所需的功能后,就可以利用「加入至对应Hook」的语法,把Hook Function自已钩到该Hook上,使得该Hook被执行到时,也会连带执行自己。

Hook机制是如何运作的?

举个例子,我们拿wp_head及wp_footer这两个内建的hook来说明,wp_head这个hook就是用来埋在负责输出标签的程式码中,而wp_footer就是用来埋在输出页尾的程式码中(定义于wp-includes/general-template.php,用wp_head()及wp_footer()包装起来)。这两个hook,主要都是在布景档案中使用的,常见会出现在header.php及footer.php中。

请看下面的情境示例图,我们把wp_head及wp_footer看成是「钩子」,而别的hook functions就能来钩住它:

我们马上来写一个简单的例子。我们要写一个hook function,就叫它print_sth(),然后把它钩上wp_head这个hook。因为wp_head()的内容实际上就只有do_action('wp_head'); 这一行内容,而wp_footer()的内容也只有do_action('wp_footer');,所以我们直接把do_action的语法换到图上去,比较容易做说明,因此示意图变成:

如此,只要执行到输出header.php时,就会执行到wp_head(),就如同执行到do_action('wp_head'),此时WP核心会去找所有「钩上」wp_head这个hook的hook function,于是就找到我们写的print_sth(),然后就执行它,所以结果它做的事就会出现在网站上,也完成了「客制」的动作:

简单的说,Hook机制就是:WP核心或其他plugin、theme提供想客制功能的人一个置入客制程式码(Hook Function)到特定的执行时间点(Hook)的机会。

WordPress的Action Hook与Filter Hook

WordPress中的Hook有两种,分别是「Action Hook」及「Filter Hook」,我们刚才举例的wp_head及wp_footer都是属于Action Hook。不过,一开始你可以先把这两种Hook看成是一样的东西,只是Filter多了一点点不同的特色,接着说明。

Action Hook

WP核心(或布景、外挂)在做它们该做的事时,如果执行到有埋action hook的程式码(即是do_action语法) 时,会去找寻对应到的hook functions,进而执行这些hook functions(即那些透过add_action()来加入的hook functions),借此完成客制功能。WP核心并不期待Action Hook functions会有回传值,所以这里的hook function只被视为一个「独立切出来运作的功能」。

WP核心做它该做的事,你做你想做的事,做完就各自结束。

Filter Hook

跟Action Hook一样,WP核心(或布景、外挂)在做它们该做的事时,如果执行到有埋filter hook的程式码(即是apply_filters语法) 时,就会去找寻对应的hook functions,进而执行这些hook functions(即那些透过add_filter()来加入的hook functions),借此完成客制功能。与Action Hook不同之处是,所有「钩上」Filter Hook的hook functions通常都会接收到参数,而WP核心会期待你拿到它提供的参数,并做完你想做的事后,要回传( return)一个值,让WP核心再利用你回传的值来接着完成它该做的事。

透过你的干涉,修改了WP核心丢给你的参数,WP核心再接着拿你改过的参数,继续完成它该做的事,此动作就像「过滤」的动作,因而得名filter。

比较Action Hook与Filter Hook的实作语法

比较一下两种Hook在埋进某处程式码时所用的语法,假设我们在某处(可能是在输出页首的程式码处,或输出文章标题、文章内容、侧边栏…等地方,要「出现客制效果」的地方)埋下这两种hook:

 

 

?

1

2

3

4

5

6

7

 

/*--------------- Action Hook ---------------*/

// 埋下一个名叫'do_more'的action hook

do_action( 'do_more' );

 

/*--------------- Filter Hook ---------------*/

// 埋下一个名叫'get_special'的filter hook,注意它会有回传值

$c  = apply_filters( 'get_special' $a ,  $b );

 

 

 

然后我们可以在某处(可能是其他外挂、functions.php等处,要「实作客制功能」的地方) 实作对应的hook function:

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

 

/*--------------- Action Hook Function---------------*/

// 增加要钩上'do_more'这个hook的hook function,

// 并为此hook function取名叫more_func。

// 第一个参数是hook名称、第二个是hook function名称

add_action( 'do_more' ,  'more_func' );

// 实作more_func的内容,不需回传值

function  more_func()

{

echo  'do more thing...' ;

}

 

/*--------------- Filter Hook Function ---------------*/

// 增加要钩上'get_special' hook的hook function,

// 并为此hook function取名叫special_func。

// 参数1是hook名称、参数2是hook function名称

// 参数3是Priority(优先序)、参数4是hook function参数的数目

add_filter( 'get_special' ,  'special_func' , 10, 2);

// 实作special_func的内容,需要给它回传值

function  special( $a ,  $b )

{

$c  =  $a ' & ' $b ;  //做一些事,例如把两个参数连接起来

return  $c ;  //回传值

}

 

 

 

所以其实两种Hook的运作方式几乎一样,只差在增加Action Hook函式不需回传值,而增加Filter Hook function时,你必须要回传一个值。所以Filter Hook函式通常都有提供参数,让想客制的人可以取得它,处理后再回传。

但如果有一个Filter Hook,它没有任何hook function有去钩它,它该怎么取得回传值?答案是,直接拿第一个它给的参数,以上面的例子来说,它会直接拿$a丢进$c。另外,其实我们也可以把filter写的跟action一样,只要不回传值就行,但action hook就没办法「模仿」filter hook,因为无法取得回传值。

Hook Function的优先序(Priority)

如果有很多地方(plugin或者布景functions.php)都add同一个hook,会怎么决定出现顺序?等案很显然是可以透过Hook Function的Priority参数来作优先序的设定:

就像我们刚才说明的例子中,我们使用add_filter加入special_func时设定的优先序是10,这也是Priority参数的预设值。如果你希望它能优先被执行,就设定小于10的数字,反之,就设个100、500之类的,让它延后被执行。

但其实这里有个隐含的冲突问题。

以wp_head这个hook为例,如果我写了一个外挂,希望透过wp_head来输出「增加a.css档案」的HTML语法,而a.css会重新设定body元素的样式,所以我希望它可以最后才被汇入,不要被其他css档干扰,于是我将Priority设为900,但我怎么知道Priority 900够不够大?若某个WP网站,它除了安装我的外挂,也安装了其他外挂,而其他外挂刚好也重新设定body元素的样式,然后把Priority设为950,此时我写的外挂在处理body样式时就出事了,于是就跟其他外挂冲突了。

所以此时我们需要了解的是:我的WP网站可能装了很多外挂,我怎么知道同一个Hook被加了多少Hook Function,而每个Hook Function的Priority被设定为多少?

答案是,我们可以透过$wp_filters这个global变数来取得所有hook的资讯,像是如下的function:

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

 

// 列出所有的hook function及其priority

function  list_hooked_functions( $tag =false)

{

global  $wp_filter ;

 

if  $tag )

{

$hook $tag ]= $wp_filter $tag ];

if  (! is_array $hook $tag ]))

{

trigger_error( "Nothing found for '$tag' hook" , E_USER_WARNING);

return ;

}

}

else

{

$hook $wp_filter ;

ksort( $hook );

}

 

echo  '<pre>' ;

foreach $hook  as  $tag  =>  $priority )

{

echo  "<br />>>>>>\t<strong>$tag</strong><br />" ;

ksort( $priority );

foreach $priority  as  $priority  =>  $function )

{

echo  $priority ;

foreach $function  as  $name  =>  $properties )  echo  "\t$name<br />" ;

}

}

echo  '</pre>' ;

return ;

}

 

 

 

当我们呼叫list_hooked_functions('wp_head'); 时,就会列出wp_head这个Hook所钩住的所有hook function,可以看到priority 10之后有好几个都没有数字,因为它们都没有特别指定priority,所以都是10,包括我们刚才写的print_sth也在其中:

>>>>> wp_head

1 wp_enqueue_scripts2 feed_links3 feed_links_extra8 wp_print_styles9 wp_print_head_scripts10 rsd_linkwlwmanifest_linkindex_rel_linkparent_post_rel_linkstart_post_rel_linkadjacent_posts_rel_link_wp_headlocale_stylesheetwp_generatorrel_canonicalwp_shortlink_wp_headprint_sthwp_admin_bar_header_admin_bar_bump_cb

所以,冲突很难提早避免,但发生冲突时,可以预先思考有没有可能是因为priority的设定,导致结果跟预期不符合。

 

文章来源:http://blog.csdn.net/lsmsilence/article/details/7348145

转载于:https://www.cnblogs.com/jocobHerbertPage/archive/2012/09/17/2689780.html

相关文章:

  • 转载:SVN分支合并
  • Mysql的Profile中的status的常量含义
  • GridView里的按钮事件
  • 通用SQL数据库查询语句精华使用简介
  • Cocoa教学:Windows OOP与Cocoa MVC之对比
  • nginx 负载均衡5种配置方式
  • js代码触发事件
  • 编译Chromium
  • WPF基础之路由事件
  • KMP算法初步认知
  • PHP 输入两个整数n 和m,从数列1,2,3.......n 中随意取几个数, 使其和等于m ,要求将其中所有的可能组合列出来...
  • 超凡蜘蛛侠
  • 简单的多进程Open×××前端控制程序
  • asymptote 中使用中文
  • Deprecated: Function ereg() is deprecated in
  • 【附node操作实例】redis简明入门系列—字符串类型
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • android图片蒙层
  • ECMAScript入门(七)--Module语法
  • es的写入过程
  • in typeof instanceof ===这些运算符有什么作用
  • js写一个简单的选项卡
  • js中的正则表达式入门
  • JWT究竟是什么呢?
  • vue的全局变量和全局拦截请求器
  • vue脚手架vue-cli
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 将回调地狱按在地上摩擦的Promise
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 入门级的git使用指北
  • 数据科学 第 3 章 11 字符串处理
  • 微信小程序设置上一页数据
  • 用Canvas画一棵二叉树
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • ​VRRP 虚拟路由冗余协议(华为)
  • #14vue3生成表单并跳转到外部地址的方式
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (day 12)JavaScript学习笔记(数组3)
  • (安卓)跳转应用市场APP详情页的方式
  • (翻译)terry crowley: 写给程序员
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (三)uboot源码分析
  • (四)Android布局类型(线性布局LinearLayout)
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (一)SpringBoot3---尚硅谷总结
  • (原創) 未来三学期想要修的课 (日記)
  • (转)IOS中获取各种文件的目录路径的方法
  • (转)ORM
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET NPOI导出Excel详解
  • .NET 反射 Reflect
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .Net(C#)自定义WinForm控件之小结篇