Как получить последовательность выполнения хуков/действий WordPress?
В каком порядке выполняются хуки add_action
?
например:
init
wp_head
wp_footer
after_theme_setup
и т.д...
???
???
???
РЕДАКТИРОВАТЬ:
Я также опубликовал свое решение.

"Данные! Данные! Данные!" — нетерпеливо воскликнул он. "Не могу сделать кирпичи без глины."
Итак, давайте соберем реальные данные из чистой установки WordPress 5.7.2 с активированной темой TwentyTwelve и всего одним текстовым виджетом.
Для главной страницы выполняются следующие вызовы do_action / do_action_ref_array
в указанном порядке (для неавторизованного пользователя):
[0] => mu_plugin_loaded
[1] => muplugins_loaded
[2] => registered_taxonomy
[3] => registered_taxonomy
[4] => registered_taxonomy
[5] => registered_taxonomy
[6] => registered_taxonomy
[7] => registered_post_type
[8] => registered_post_type
[9] => registered_post_type
[10] => registered_post_type
[11] => registered_post_type
[12] => registered_post_type
[13] => registered_post_type
[14] => registered_post_type
[15] => registered_post_type
[16] => registered_post_type
[17] => plugins_loaded
[18] => sanitize_comment_cookies
[19] => wp_roles_init
[20] => setup_theme
[21] => unload_textdomain
[22] => load_textdomain
[23] => after_setup_theme
[24] => load_textdomain
[25] => load_textdomain
[26] => auth_cookie_malformed
[27] => set_current_user
[28] => init
[29] => registered_post_type
[30] => registered_post_type
[31] => registered_post_type
[32] => registered_post_type
[33] => registered_post_type
[34] => registered_post_type
[35] => registered_post_type
[36] => registered_post_type
[37] => registered_post_type
[38] => registered_post_type
[39] => registered_taxonomy
[40] => registered_taxonomy
[41] => registered_taxonomy
[42] => registered_taxonomy
[43] => registered_taxonomy
[44] => widgets_init
[45] => register_sidebar
[46] => register_sidebar
[47] => register_sidebar
[48] => wp_register_sidebar_widget
[49] => wp_register_sidebar_widget
[50] => wp_register_sidebar_widget
[51] => wp_register_sidebar_widget
[52] => wp_register_sidebar_widget
[53] => wp_register_sidebar_widget
[54] => wp_register_sidebar_widget
[55] => wp_register_sidebar_widget
[56] => wp_register_sidebar_widget
[57] => wp_register_sidebar_widget
[58] => wp_register_sidebar_widget
[59] => wp_register_sidebar_widget
[60] => wp_register_sidebar_widget
[61] => wp_register_sidebar_widget
[62] => wp_register_sidebar_widget
[63] => wp_register_sidebar_widget
[64] => wp_default_scripts
[65] => wp_register_sidebar_widget
[66] => wp_register_sidebar_widget
[67] => wp_register_sidebar_widget
[68] => wp_register_sidebar_widget
[69] => wp_register_sidebar_widget
[70] => wp_register_sidebar_widget
[71] => wp_register_sidebar_widget
[72] => wp_register_sidebar_widget
[73] => wp_register_sidebar_widget
[74] => wp_register_sidebar_widget
[75] => wp_register_sidebar_widget
[76] => wp_register_sidebar_widget
[77] => wp_register_sidebar_widget
[78] => wp_register_sidebar_widget
[79] => wp_register_sidebar_widget
[80] => wp_register_sidebar_widget
[81] => wp_register_sidebar_widget
[82] => wp_register_sidebar_widget
[83] => wp_register_sidebar_widget
[84] => wp_register_sidebar_widget
[85] => wp_register_sidebar_widget
[86] => wp_register_sidebar_widget
[87] => wp_register_sidebar_widget
[88] => wp_register_sidebar_widget
[89] => wp_register_sidebar_widget
[90] => wp_register_sidebar_widget
[91] => wp_register_sidebar_widget
[92] => wp_register_sidebar_widget
[93] => wp_register_sidebar_widget
[94] => wp_sitemaps_init
[95] => wp_loaded
[96] => parse_request
[97] => send_headers
[98] => parse_tax_query
[99] => parse_query
[100] => pre_get_posts
[101] => posts_selection
[102] => wp
[103] => template_redirect
[104] => get_header
[105] => wp_head
[106] => wp_enqueue_scripts
[107] => wp_default_styles
[108] => enqueue_block_assets
[109] => wp_print_styles
[110] => wp_print_scripts
[111] => wp_body_open
[112] => parse_tax_query
[113] => parse_query
[114] => pre_get_posts
[115] => parse_tax_query
[116] => posts_selection
[117] => parse_tax_query
[118] => parse_query
[119] => pre_get_posts
[120] => parse_tax_query
[121] => posts_selection
[122] => parse_tax_query
[123] => parse_query
[124] => pre_get_posts
[125] => parse_tax_query
[126] => posts_selection
[127] => parse_tax_query
[128] => parse_query
[129] => pre_get_posts
[130] => parse_tax_query
[131] => posts_selection
[132] => parse_term_query
[133] => pre_get_terms
[134] => loop_start
[135] => the_post
[136] => get_template_part_content
[137] => get_template_part
[138] => parse_comment_query
[139] => pre_get_comments
[140] => parse_comment_query
[141] => pre_get_comments
[142] => comment_form_comments_closed
[143] => loop_end
[144] => get_sidebar
[145] => dynamic_sidebar_before
[146] => dynamic_sidebar
[147] => dynamic_sidebar_after
[148] => get_footer
[149] => twentytwelve_credits
[150] => wp_footer
[151] => wp_print_footer_scripts
[152] => shutdown
используя must-use плагин:
add_action( 'all', function ( $tag ) {
static $hooks = array();
// Только хуки do_action / do_action_ref_array.
if ( did_action( $tag ) ) {
$hooks[] = $tag;
}
if ( 'shutdown' === $tag ) {
print_r( $hooks );
}
} );
который выводит собранные хуки действий для текущей страницы в последнем доступном действии ядра (shutdown).
Если вы хотите проверить порядок действий и количество их вызовов, можно использовать например:
add_action ( 'shutdown', function(){
print_r ( $GLOBALS['wp_actions'] );
} );
или без явного использования глобальных переменных:
add_action ( 'shutdown', function() use ( &$wp_actions ) {
print_r ( $wp_actions );
} );
что выводит массив:
[mu_plugin_loaded] => 1
[muplugins_loaded] => 1
[registered_taxonomy] => 10
[registered_post_type] => 20
[plugins_loaded] => 1
[sanitize_comment_cookies] => 1
[wp_roles_init] => 1
[setup_theme] => 1
[unload_textdomain] => 1
[load_textdomain] => 3
[after_setup_theme] => 1
[auth_cookie_malformed] => 1
[set_current_user] => 1
[init] => 1
[widgets_init] => 1
[register_sidebar] => 3
[wp_register_sidebar_widget] => 45
[wp_default_scripts] => 1
[wp_sitemaps_init] => 1
[wp_loaded] => 1
[parse_request] => 1
[send_headers] => 1
[parse_tax_query] => 9
[parse_query] => 5
[pre_get_posts] => 5
[posts_selection] => 5
[wp] => 1
[template_redirect] => 1
[get_header] => 1
[wp_head] => 1
[wp_enqueue_scripts] => 1
[wp_default_styles] => 1
[enqueue_block_assets] => 1
[wp_print_styles] => 1
[wp_print_scripts] => 1
[wp_body_open] => 1
[parse_term_query] => 1
[pre_get_terms] => 1
[loop_start] => 1
[the_post] => 1
[get_template_part_content] => 1
[get_template_part] => 1
[parse_comment_query] => 2
[pre_get_comments] => 2
[comment_form_comments_closed] => 1
[loop_end] => 1
[get_sidebar] => 1
[dynamic_sidebar_before] => 1
[dynamic_sidebar] => 1
[dynamic_sidebar_after] => 1
[get_footer] => 1
[twentytwelve_credits] => 1
[wp_footer] => 1
[wp_print_footer_scripts] => 1
[shutdown] => 1
где мы можем получить общее количество с помощью echo array_sum( $GLOBALS['wp_actions'] );
Вот более читаемая версия:
add_action ( 'shutdown', function() {
foreach ( $GLOBALS['wp_actions'] as $action => $count ) {
printf( '%s (%d) <br/>' . PHP_EOL, $action, $count );
}
} );
или без явного использования глобальных переменных:
add_action ( 'shutdown', function() use ( &$wp_actions ) {
foreach ( $wp_actions as $action => $count ) {
printf( '%s (%d) <br/>' . PHP_EOL, $action, $count );
}
} );
чтобы получить следующий список:
mu_plugin_loaded (1)
muplugins_loaded (1)
registered_taxonomy (10)
registered_post_type (20)
plugins_loaded (1)
sanitize_comment_cookies (1)
wp_roles_init (1)
setup_theme (1)
unload_textdomain (1)
load_textdomain (3)
after_setup_theme (1)
auth_cookie_malformed (1)
set_current_user (1)
init (1)
widgets_init (1)
register_sidebar (3)
wp_register_sidebar_widget (45)
wp_default_scripts (1)
wp_sitemaps_init (1)
wp_loaded (1)
update_option (1)
update_option__transient_doing_cron (1)
updated_option (1)
set_transient_doing_cron (1)
setted_transient (1)
requests-requests.before_request (1)
requests-curl.before_request (1)
http_api_curl (1)
requests-curl.before_send (1)
requests-curl.after_send (1)
requests-curl.after_request (1)
requests-requests.before_parse (1)
http_api_debug (1)
parse_request (1)
send_headers (1)
parse_tax_query (9)
parse_query (5)
pre_get_posts (5)
posts_selection (5)
wp (1)
template_redirect (1)
get_header (1)
wp_head (1)
wp_enqueue_scripts (1)
wp_default_styles (1)
enqueue_block_assets (1)
wp_print_styles (1)
wp_print_scripts (1)
wp_body_open (1)
parse_term_query (1)
pre_get_terms (1)
loop_start (1)
the_post (1)
get_template_part_content (1)
get_template_part (1)
parse_comment_query (2)
pre_get_comments (2)
comment_form_comments_closed (1)
loop_end (1)
get_sidebar (1)
dynamic_sidebar_before (1)
dynamic_sidebar (1)
dynamic_sidebar_after (1)
get_footer (1)
twentytwelve_credits (1)
wp_footer (1)
wp_print_footer_scripts (1)
shutdown (1)
P.S.: Также рекомендую отличный плагин Query Monitor от John Blackbourn. (Я не имею отношения к этому плагину)

Спасибо, что упомянули Query Monitor. Похоже, в этом случае это полезный плагин.

@kraftner спасибо за обновление, я всегда планировал (но забывал об этом) добавить прямую ссылку на саму историю как надёжный источник, очевидно, мои навыки поиска Шерлока Холмса в тот момент были не на высоте ;-)

Мне понравилась цитата, и я захотел увидеть больше контекста. Раз уж у меня уже была ссылка для себя, почему бы не обновить её и здесь. :)

Запись старше 4 лет, но всё ещё полезна. Большое спасибо!

Это не даёт точной последовательности из-за группировки по имени хука.

@Walf Пожалуйста, ознакомьтесь с обновлённым ответом для WP 5.7.2 и mu-плагина.

Ваш обновленный ответ стал значительно лучше. Однако он может вообще не выводить ничего, если выполнение прервется из-за ошибки. Конечно, ошибка указывает, где она произошла, но знание предшествующих событий может быть крайне полезным. Кроме того, использование операторов print/dump может помешать запросу или вообще не сработать, если запрос завершается досрочно.

WordPress регистрирует shutdown action hook как shutdown-функцию с помощью PHP register_shutdown_function( 'shutdown_action_hook' )
, поэтому она выполнится в конце, даже если, например, callback другого хука вызывает exit()
, инициирует ошибку с помощью trigger_error()
или выбрасывает неперехваченный Error. Согласно комментарию в документации PHP, она также должна выполняться после таймаута. Да, вывод не отобразится, если fastcgi_finish_request его обрывает, но я думаю, можно залогировать вывод, если печать является проблемой.


Добавьте хотя бы источник, или еще лучше: найдите дубликат этого вопроса.

Честно говоря, я не знаю, откуда я это взял. У меня это изображение было сохранено на компьютере. В противном случае я бы так и сделал.

Это также опубликовано на домашней странице Тома МакФарлина: The WordPress Page Lifecycle -> https://tommcfarlin.com/wordpress-page-lifecycle/

Решение найдено!
Спасибо @birgire за отличный ответ. Я добавлю к этому, что muplugins_loaded
иногда не срабатывает, поэтому я буду использовать plugins_loaded
как самый ранний хук (но в этот момент авторизация пользователя еще не выполнена. Если вам нужно проверить авторизацию пользователя, то init
- это самый ранний вариант для этого)...
P.S. Существуют отличные плагины:
1) Query Monitor - Вы можете увидеть все, что происходит при загрузке страницы, включая продолжительность выполнения каждой функции и многое другое (посмотрите все скриншоты на странице плагина):
2) WP-DEBUG-BAR + WP-DEBUG-SLOW-ACTIONS:
a) список выполненных хуков (действий) на вашем сайте.
b) Продолжительность каждого действия (не функции):

Базовую последовательность действий также можно найти в официальной документации:

Это похоже на ответ @birgire, но предоставляет удобный отчет, который можно отобразить для любого URL на сайте WordPress. Вам нужно войти в систему как пользователь с правами администратора, затем добавить ?wp-hooks
в конец URL, который вы хотите протестировать.
/**
* Справочник по хукам WordPress
*
* Выводит все хуки действий и фильтров внизу любой страницы
* путем добавления ?wp-hooks к URL, когда вы вошли в систему
* как пользователь с уровнем администратора.
*/
function kevinlearynet_hooks_reference() {
// Показывается только для пользователей с правами администратора при добавлении ?list-wp-hooks к URL
$trigger = isset( $_GET['wp-hooks'] ) && current_user_can( 'manage_options' );
if ( ! $trigger ) return;
// Сбор и сортировка фильтров и хуков
$filters = array_keys( $GLOBALS['wp_filter'] );
sort( $filters );
$actions = array_keys( $GLOBALS['wp_actions'] );
// Вывод шаблона
ob_start();
?>
<section class="wp-hooks">
<h1 class="wp-hooks__h1">Справочник по хукам WordPress</h1>
<div class="wp-hooks__lists">
<div class="wp-hooks__col">
<h2 class="wp-hooks__h2">Действия</h2>
<?php foreach ( $actions as $hook ) : ?>
<p class="wp-hooks__hook"><?php echo $hook; ?></p>
<?php endforeach; ?>
</div>
<div class="wp-hooks__col">
<h2 class="wp-hooks__h2">Фильтры</h2>
<?php foreach ( $filters as $hook ) : ?>
<p class="wp-hooks__hook"><?php echo $hook; ?></p>
<?php endforeach; ?>
</div>
</div>
</section>
<style>
.wp-hooks {
padding: 30px;
margin: 30px;
border-radius: 4px;
background: white;
font-size: 16px;
line-height: 1.4;
height: 50vh;
min-height: 500px;
overflow-y: scroll;
}
.wp-hooks__lists {
display: flex;
}
.wp-hooks__col {
flex: 1;
width: 50%;
}
.wp-hooks__h1 {
margin: 0 0 20px;
}
.wp-hooks__h2 {
line-height: 1;
font-size: 18px;
margin: 0 0 10px;
}
.wp-hooks__hook {
padding: 0;
margin: 0;
}
</style>
<?php
ob_end_flush();
}
add_action( 'shutdown', 'kevinlearynet_hooks_reference' );
Результат выглядит следующим образом:
Я написал об этом на своем сайте, так что вот оригинальный источник для справки. Там содержится немного больше деталей о решениях, связанных с сортировкой и функциональностью.

Нет двух абсолютно одинаковых запросов.
Быстрый и грязный, но очень точный способ выяснить, что происходит — это временно добавить строки в начало функций do_action
и do_action_ref_array
в файле wp-includes/plugin.php
, чтобы логировать каждый хук, например:
if (isset($some_trigger_from_get_post_head_etc)) file_put_contents(ABSPATH . 'hooks.log', "$hook_name\n", FILE_APPEND);
Возможно, стоит сделать то же самое для функций apply_filters
и apply_filters_ref_array
в том же файле.
Я не нашел лучшего способа получить полную хронологическую последовательность, включая хуки, которые срабатывают еще до загрузки must-use плагинов и после shutdown
.
