WordPress的Action加载顺序

写WordPress代码时需要不停的与hooks(actions and filters)打交道,filter就像茶壶的过滤嘴,茶壶在哪它就在哪,顺序问题不那么重要。而action是一种行为,比如掀起壶盖和盖上壶盖之间 就可以放一个action,在这个action里可以放茶叶,不掀起壶盖是不可以放茶叶的,所以actions执行的顺序很重要。

 

钩子Hooks

钩子是让一段代码与另一段代码做交互的方法。它们是插件、主题与WordPress内核做交互的基础,当然WordPress内核里也广泛使用了。

钩子有两种:Actions和Filters。使用它们,你必须写一个回调函数,然后将它注册到WordPress关联到特定action或filter。

Filters让你可以在WordPress运行的时候修改一段数据的值。传入给回调函数的变量修改后被返回。它们是独立工作的,不会影响到函数外部的东西。

Actions则相反,允许你增加或修改WordPress的运行。回调函数会运行在WordPress运行到特定点的时候,可以做一些任务,比如:输出显示给用户、插入数据到数据库。

WordPress提供了许多钩子供你使用,你也可以自定义一些供其他开发者来修改你的插件或主题。

 

Actions

Actions钩子提供了函数一种方法可以让其他函数挂靠上来,然后额外的代码就可以在WordPress内核、插件、主题运行到特定点的时候执行了。

它们通过调用add_action()函数来工作,传入两个参数:你要挂靠的钩子名称、要运行的回调函数。比如:

<?php add_action( 'init', 'do_some_stuff' ); ?>

以上语句中,自定义do_some_stuff()函数会在WordPress运行init操作的时候被调用。

可以去代码参考的hook部分查看更多可用的action。如你经验丰富,对WordPress内核十分熟悉,可以直接去源代码里找合适的action。

示例

如果你想为Loop修改MySQL查询语句,你可以挂靠到pre_get_posts操作上。比如,你可以将指定CPT包含到搜索中:

<?php
function search_filter( $query ) {
    if ( ! is_admin() && $query->is_main_query() ) {
        if ( $query->is_search ) {
            $query->set( 'post_type', array( 'post', 'movie' ) );
        }
    }
}
add_action( 'pre_get_posts', 'search_filter' );
?>

还有比如,你想添加标签到HTML的<head>里,你可以挂靠到wp_head操作上。

<?php
function prevent_google_maps_resize() {
    echo '<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />';
}
add_action( 'wp_head', 'prevent_google_maps_resize' );
?>

非常重要的一个 url地址, 关于wordpress的

https://github.com/66beta/plugin-handbook-chs/blob/master/4.Hooks.md

 

 

WordPress中的actions

actions可以理解为一组在系统加载到某一时刻要执行的functions集合,使用do_action()添加,例如我们经常用到的get_header()函数,是这样定义的

1
2
3
4
5
6
7
8
9
10
11
12
13
function get_header( $name = null ) {
    do_action( 'get_header', $name );
    $templates = array();
    if ( isset($name) )
        $templates[] = "header-{$name}.php";
    $templates[] = 'header.php';
    // Backward compat code will be removed in a future release
    if ('' == locate_template($templates, true))
        load_template( ABSPATH . WPINC . '/theme-compat/header.php');
}

函数第二行用do_action()注册了一个action,叫做get_header

1
do_action( 'get_header', $name );

如果我们在functions.php中或者插件中写

1
add_action('get_header','my_fun')

my_fun()这个函数就会在do_action的位置执行,而不是在functions.php运行的位置执行。

Actions的执行顺序

了解WordPress中actions的执行顺序,可以知晓在这个action执行时,是否已经具备某些资源,例如登陆用户信心、例如插件API等。

要了解Actions的执行顺序,可以安装一个开发人员的插件WordPress Hook Sniffer,该插件不仅能告知actions的加载顺序,还能知道当前页面add_action操作有哪些,remove_action操作有哪些,还有filters信息。

这个simply-show-hooks插件也很好, 用来显示hook。

用这个插件查看了安装默认主题时action的执行顺序,捡了一些重要的记录下来,红色字体标记了一下比较重要的阶段。

muplugins_loaded (最先加载的action)

registered_taxonomy

registered_post_type

(加载所有激活的插件的文件,这是插件代码被执行的位置)

plugins_loaded

sanitize_comment_cookies

setup_theme

(载入当前主题的functions.php,functions.php中没有用add_filter或add_action添加的函数在这里被执行)

after_setup_theme (这个钩子看着眼熟吧,默认主题开头就有)

auth_cookie_malformed

auth_cookie_valid

set_current_user (这里执行了wp_set_current_user()函数,全局变量$current_user产生)

init

widgets_init

register_sidebar

wp_register_sidebar_widget

wp_default_scripts

wp_default_styles

admin_bar_init

add_admin_bar_menus

wp_loaded

parse_request

send_headers

parse_query

pre_get_posts

posts_selection

wp

template_redirect

加载激活的主题的模板(例如index.php、page.php等)

get_header

wp_head

wp_enqueue_scripts

wp_print_styles

wp_print_scripts

wp_print_scripts

get_footer

wp_footer

从上面的列表中可以看出一些问题:

  • 插件文件比主题的functions.php加载更早
  • 插件加载时,wp_set_current_user()尚未执行,因此在插件文件的body中无法直接获取用户信息
  • init和after_setup_theme的区别是,后者执行时尚未调用wp_set_current_user(),没有授权用户信息
  • 加 载主题模板文件发生在最后阶段,此阶段中不管是插件的代码还是functions.php中的代码都已执行,这样我们就不奇怪为什么在 single.php中调用query_posts()会增加查询次数,query_posts()大约在pre_get_posts的位置就执行完了, 等程序执行到single.php时,如果调用query_posts,只能推翻前面的结果重新查一遍。我们还能看出,避免这个问题的方法就是在 functions.php中使用filters函数(posts_join, posts_groupby等)更改query_posts的查询参数,因为functions.php早于query_posts执行,方法可以参考《自定义WordPress查询的4种方法》中的第三种方法。

理解万岁

与其枯燥的去记忆什么时候该用哪个action,不如理解一下WordPress的启动过程,了解actions加载的顺序,记忆几个比较重要的过程,例如哪些actions发生在插件代码执行以后,哪些actions发生在functions.php加载以后。

发表评论