¿Cómo obtener la secuencia de ejecución de hooks/acciones de WordPress?

29 sept 2014, 10:59:23
Vistas: 58.6K
Votos: 67

¿En qué orden se ejecutan los hooks de add_action?

es decir,

init
wp_head
wp_footer
after_theme_setup 
etc...
???
???
???



EDICIÓN:

También he publicado mi solución.

1
Comentarios

nota, los datos de BACK-END vs FRONT-END difieren

T.Todua T.Todua
4 oct 2024 20:45:24
Todas las respuestas a la pregunta 6
13
123

"¡Datos! ¡Datos! ¡Datos!" gritó impacientemente. "No puedo hacer ladrillos sin arcilla."

Sherlock Holmes - La aventura de los alisos de cobre

Así que vamos a recopilar algunos datos reales de una instalación limpia de WordPress 5.7.2 con el tema TwentyTwelve activado y solo un widget de texto.

Para la página de inicio, se realizan las siguientes llamadas do_action / do_action_ref_array en el siguiente orden (sin sesión iniciada):

[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

usando el plugin must-use:

add_action( 'all', function ( $tag ) {
    static $hooks = array();
    // Solo hooks do_action / do_action_ref_array.
    if ( did_action( $tag ) ) {
        $hooks[] = $tag;
    }
    if ( 'shutdown' === $tag ) {
        print_r( $hooks );
    }
} );

que imprime los hooks de acción recopilados, para la página actual, en la última acción disponible del núcleo (shutdown).

Si quieres comprobar el orden de las acciones y cuántas veces se dispara cada una, entonces puedes usar por ejemplo:

add_action ( 'shutdown', function(){
    print_r ( $GLOBALS['wp_actions'] );         
} );

o sin globals explícitos:

add_action ( 'shutdown', function() use ( &$wp_actions ) {
    print_r ( $wp_actions );      
} );

que devuelve el array:

[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

donde podemos obtener el conteo total con echo array_sum( $GLOBALS['wp_actions'] );

Aquí hay una versión más bonita:

add_action ( 'shutdown', function() {
    foreach ( $GLOBALS['wp_actions'] as $action => $count ) {
        printf( '%s (%d) <br/>' . PHP_EOL, $action, $count );
    }
} );

o sin globals explícitos:

add_action ( 'shutdown', function() use ( &$wp_actions ) {
    foreach ( $wp_actions as $action => $count ) {
        printf( '%s (%d) <br/>' . PHP_EOL, $action, $count );
    }
} );

para obtener la siguiente lista:

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)

PD: También deberías echar un vistazo al excelente plugin Query Monitor de John Blackbourn. (No tengo relación con este plugin)

29 sept 2014 12:04:02
Comentarios

¡Muy bonito, sin duda!

jdm2112 jdm2112
19 mar 2015 21:30:32

Gracias por mencionar Query Monitor. Parece ser un plugin útil en este caso.

D.A.H D.A.H
16 oct 2015 12:53:37

@kraftner gracias por la actualización, siempre tuve planeado (pero lo olvidé) enlazar directamente a la historia misma como fuente adecuada, obviamente mis habilidades de búsqueda estilo Sherlock Holmes no eran muy buenas en ese momento ;-)

birgire birgire
1 mar 2017 15:22:07

Me gustó la cita y quería ver más contexto. Y como ya tenía el enlace para mí, ¿por qué no actualizarlo aquí también? :)

kraftner kraftner
1 mar 2017 16:22:28

Esto debería ser parte del codex, lo digo en serio.

Johansson Johansson
13 jul 2017 19:54:45

Me alegra saber que ayuda @JackJohansson

birgire birgire
13 jul 2017 21:22:13

Publicación de más de 4 años y aún útil. ¡Muchas gracias!

Sebastian Kaczmarek Sebastian Kaczmarek
5 feb 2019 12:15:21

Esto no obtiene la secuencia exacta debido a la agrupación por nombre de hook.

Walf Walf
12 jul 2021 06:28:28

@Walf Por favor, consulta la respuesta actualizada para WP 5.7.2 y el mu-plugin.

birgire birgire
12 jul 2021 13:49:56

Tu respuesta actualizada es una mejora significativa. Sin embargo, puede que no genere ningún resultado si un error detiene la ejecución. Por supuesto, un error te indica dónde ocurrió, pero conocer los eventos anteriores puede ser extremadamente útil. Además, el uso de declaraciones print/dump probablemente interferirá con la solicitud, o se anulará por completo si finalizas la solicitud antes de tiempo.

Walf Walf
13 jul 2021 04:35:37

WordPress registra el hook de acción shutdown como una función de shutdown con PHP register_shutdown_function( 'shutdown_action_hook' ), por lo que se ejecutará al final incluso si, por ejemplo, el callback de otro hook llama a exit(), provoca un error con trigger_error() o lanza un Error no capturado. Según un comentario en la documentación de PHP, también debería ejecutarse después de un timeout. Sí, no se mostrará si fastcgi_finish_request lo corta, pero creo que se podría registrar en un log si imprimir es un problema.

birgire birgire
13 jul 2021 15:06:28

Sigue siendo útil en 2022: ¡gracias!

Gas Gas
29 sept 2022 12:50:15

Me alegra saber que sigue siendo útil @Gas

birgire birgire
29 sept 2022 14:00:56
Mostrar los 8 comentarios restantes
3
28

Aquí está el gráfico de carga de WordPress

Gráfico de carga de WordPress

Fuente por @Rarst

29 sept 2014 11:04:06
Comentarios

Añade al menos la fuente, o mejor aún: encuentra un duplicado para esta pregunta.

fuxia fuxia
29 sept 2014 11:36:59

En realidad no sabía de dónde lo obtuve. Tenía esta imagen guardada en mi PC. De lo contrario lo habría hecho.

Robert hue Robert hue
29 sept 2014 11:43:44

También está publicado en la página de inicio de Tom Mc Farlin: The WordPress Page Lifecycle -> https://tommcfarlin.com/wordpress-page-lifecycle/

D.A.H D.A.H
16 oct 2015 13:05:24
0

¡Solución encontrada!

Gracias @birgire por la excelente respuesta. Añadiré a eso que muplugins_loaded a veces no se ejecuta, así que usaré plugins_loaded como el hook más temprano (pero en ese momento, la autorización de usuario aún no se ha realizado. Si deseas verificar la autorización del usuario, entonces init es el más temprano para eso)...

P.D. existen excelentes plugins:

1) Query Monitor - Puedes ver todo lo que ocurre durante la carga de la página, es decir, la duración de cada función ejecutada y mucho más (ver todas las capturas de pantalla en la página del plugin):

Monitor de consultas WordPress - Herramienta de depuración

2) WP-DEBUG-BAR + WP-DEBUG-SLOW-ACTIONS:
a) lista de depuración de hooks(acciones) ejecutados en tu sitio.
b) Ver la duración de cada acción (no función): Barra de depuración WordPress - Monitoreo de acciones

23 dic 2017 22:22:50
0

La secuencia básica también se puede encontrar en la documentación oficial:

https://codex.wordpress.org/Plugin_API/Action_Reference

28 may 2018 17:57:16
0

Esto es similar a la respuesta de @birgire, pero proporciona un informe detallado que se puede mostrar para cualquier URL en un sitio WordPress. Necesitarás estar logueado como un usuario de nivel Administrador, luego agregar ?wp-hooks al final de la URL que deseas probar.

/**
* Referencia de Hooks de WordPress
*
* Muestra todos los hooks de acción y filtro al final de cualquier página
* agregando ?wp-hooks al final de la URL mientras estás logueado
* como un usuario de nivel Administrador.
*/
function kevinlearynet_hooks_reference() {

    // Solo se muestra para usuarios de nivel Administrador cuando se agrega ?list-wp-hooks a la URL
    $trigger = isset( $_GET['wp-hooks'] ) && current_user_can( 'manage_options' );
    if ( ! $trigger ) return;

    // Captura y ordena filtros y hooks
    $filters = array_keys( $GLOBALS['wp_filter'] );
    sort( $filters );
    $actions = array_keys( $GLOBALS['wp_actions'] );

    // Genera el template básico
    ob_start();
    ?>
    <section class="wp-hooks">
    <h1 class="wp-hooks__h1">Referencia de Hooks de WordPress</h1>
    <div class="wp-hooks__lists">
    <div class="wp-hooks__col">
    <h2 class="wp-hooks__h2">Acciones</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">Filtros</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' );

La salida se ve así:

Ejemplo de referencia de hooks en WordPress

Escribí sobre esto en mi propio blog, aquí está la fuente original como referencia. Incluye un poco más de detalle sobre las decisiones detrás del ordenamiento y funcionalidad.

5 may 2020 18:44:11
0

No hay dos solicitudes exactamente iguales. Una forma rápida y sucia pero muy precisa de descubrir lo que está sucediendo es temporalmente agregar líneas al inicio de las funciones do_action y do_action_ref_array en wp-includes/plugin.php para registrar cada hook, por ejemplo:

if (isset($some_trigger_from_get_post_head_etc)) file_put_contents(ABSPATH . 'hooks.log', "$hook_name\n", FILE_APPEND);

Puede que quieras hacer lo mismo con las funciones apply_filters y apply_filters_ref_array en el mismo archivo. No he encontrado una mejor manera de obtener la secuencia completa y cronológica, incluyendo hooks que se ejecutan antes de que incluso se carguen los plugins must-use y después de shutdown.

24 nov 2017 10:48:48