Identifier les fonctions appelées par certains hooks WordPress

Durant un développement de plugin WordPress pour un client, j’ai récemment eu besoin de lister toutes les fonctions appelées sur tous les hooks WooCommerce qui modifient le statut d’une commande.

Je présente ici une fonction permettant de nous aider à cibler ces fonctions, sans connaitre le nom précis de tous les hooks à investiguer.

Conseil

Cette fonction fait partie de mon Must-use plugin msk-devtools (que j’intègre à tous mes développements WordPress) qui offre quelques fonctions récurrentes bien pratiques pour faciliter notre tâche de développeur WordPress. N’hésitez pas à le télécharger et l’installer !

Débugger les hooks WordPress et les fonctions appelées

Utiliser Query Monitor

L’excellente extension Query Monitor nous donne déjà de précieuses informations au sujet des hooks chargés sur une page d’un site WordPress, comme on peut le voir sur l’image ci-dessous.

Listing des hooks appelés sur la page en cours grâce à Query Monitor

Mais analyser cette liste de hooks, pour débugger un comportement précis, peut vite devenir être une tâche titanesque vu le nombre d’actions et filtres appelés par WordPress, le thème et les plugins actifs.

Mais alors…

Comment inspecter tout ce qu’il se passe sur plusieurs hooks WordPress spécifiques à la fois ?

Grâce à une petite fonction créée rien que pour ça !

<?php
/**
 * Inspect/list functions called on hooks containing specific term
 *
 * @param array Array of terms that the hook should contain
 * @return array
 */
function inspect_hooks( $terms = [ 'wp_' ] ) {
	global $wp_filter;
	$related_hooks = [];
	$total         = 0;

	if ( ! is_array( $terms ) ) {
		$terms = [ $terms ];
	}

	foreach ( $wp_filter as $key => $val ) {
		if ( string_contains_all_words( $key, $terms ) ) {
			foreach ( $val->callbacks as $priority ) {
				foreach ( $priority as $callback ) {
					foreach ( $callback as $function => $function_data ) {
						if ( $function !== 'function' ) {
							continue;
						}

						if ( is_array( $function_data ) ) {
							$method = $function_data[1];

							if ( is_string( $function_data[0] ) ) {
								$classname = $function_data[0];
							} else {
								$classname = get_class( $function_data[0] );
							}

							if ( method_exists( $function_data[0], $method ) ) {
								$reflection    = new \ReflectionMethod( $classname, $method );
								$function_name = $classname . '->' . $method;
								$related_hooks[ $key ][] = sprintf( '<strong>%1$s</strong> in <em>%2$s</em> <small>L%3$d</small>', $function_name, str_replace( ABSPATH, '', $reflection->getFileName() ), $reflection->getStartLine() );
							} else {
								$function_name = $classname . '->' . $method;
								$related_hooks[ $key ][] = sprintf( '<strong>%1$s</strong> (method not found)', $function_name );
							}
						} else {
							$reflection = new \ReflectionFunction( $function_data );

							if ( $function_data instanceof \Closure ) {
								$related_hooks[ $key ][] = sprintf( 'closure in <em>%1$s</em> <small>L%2$d</small>', str_replace( ABSPATH, '', $reflection->getFileName() ), $reflection->getStartLine() );
							} else {
								$related_hooks[ $key ][] = sprintf( '<strong>%3$s</strong> in <em>%1$s</em> <small>L%2$d</small>', str_replace( ABSPATH, '', $reflection->getFileName() ), $reflection->getStartLine(), $function_data );
							}
						}

						$total++;
					}
				}
			}
		}
	}

	$related_hooks['total'] = $total;

	return $related_hooks;
}

/**
 * Check if a string contains ALL words from an array
 *
 * @param array $array Array of strings
 * @return boolean
 */
function string_contains_all_words( $string, $array ) {
	$missed = false;

	foreach ( $array as $word ) {
		if ( strpos( $string, $word ) !== false ) {
			continue;
		} else {
			$missed = true;
			break;
		}
	}

	return ! $missed;
}

Utilisation

inspect_hooks( [ 'woocommerce', 'status' ] )

Va nous renvoyer la liste de tous les hooks contenant le mot woocommerce et status et nous indiquer toutes les fonctions (ou méthodes de classes, ou fonctions anonymes) appelées par ces hooks.

Pour chaque fonction appelée sur un hook, on peut savoir de quel fichier elle provient et à quelle ligne elle est enregistrée. Il suffit de faire un var_dump() de ce qui est retourné pour afficher ces données !

Utilité

Une petite fonction utilitaire fort pratique pour pouvoir analyser ce qu’il se passe derrière des événements WordPress spécifiques sans trop savoir les noms officiels des hooks déclenchés.

Par exemple :

  • inspect_hooks( [ 'wp', 'footer' ] ) va nous dire tout ce qui est déclenché dans le footer de notre site
  • inspect_hooks( [ 'woocommerce', 'cart' ] ) va nous lister tout ce qu’il se passe autour du panier WooCommerce
  • inspect_hooks( [ 'gform' ] ) va nous permettre de savoir toutes les fonctions qui s’injectent dans la logique de Gravity Forms

Grâce à cela, on va pouvoir en apprendre un peu plus sur toutes les logiques déclenchées lors d’événements précis. Super pratique, par exemple, pour découvrir tous les plugins qui ajoutent de nouveaux comportements sur certains événements WordPress. Actions et filtres compris !

Qui fait quoi quand une commande WooCommerce change de statut ? Quel plugin déclenche des fonctionnalités quand un commentaire est publié ? D’où vient cette fonction qui s’exécute à chaque fois qu’un article est publié ?

Plutôt pratique, non 😉 ?


Vous avez aimé cet article ?

Partagez-le sur vos réseaux sociaux en guise de remerciement :)


1 commentaire

Bonjour
Très intéressant comme fonction.
Je suis débutant en code wordpress ; est-il possible d’expliquer ou je dois placer ce plugin, ou je dois écrire « inspect_hooks » ?
Merci d’avance

Laisser un commentaire