Hooks (filters and actions) in WordPress are extremely powerful, but also complex with “lots of moving parts”. Diagnosing problems requires a lot of manual work. Having a road map of calls to add_action, add_filter, apply_filters, do_action, and do_action_ref_array for a particular code base would be handy.
There is no easy way to capture the various hooks and calls to them in WordPress. Domain-specific documentation is weak or non-existent.
We looked high and low for a utility that did this, but none existed.
phpDoucmentor and similar tools don’t go “inside” functions where most of the hooks and related calls are located. So we wrote WP-FASE to do this.
What is it?
Hoping to extend an existing tool, we tried to add to the latest incarnation of phpDocumentor, but the code was in alpha state at best.
The next approach was to analyze code and extract only the parts we needed.
It was starting to look like we were going to be in Regular Expression hell for the foreseeable future, analyzing lots of code, trying to figure out how to get parameters, docblocks and other goodies related to the hook calls.
After a few minutes of regex despair I started to do a little research and discovered the PHP Tokenizer, a built-in extension since PHP 4.3.0.
The tokenizer splits arbitrary source (or any length) into an array of PHP tokens. These PHP tokens are very valuable pieces of information and eliminate the need for complicated regular expressions and other lexical gymnastics.
The array elements returned by the tokenizer contain either a single character (;, ., >, !, etc.) or a three-element array containing the token index in element 0, the string content of the original token in element 1 and the line number in element 2 (as of 5.2.2).
I have found it beneficial to define constants for the various token pieces (TOKEN_INDEX, TOKEN_STRING, TOKEN_LINE_NUMBER) in order to avoid magic numbers.
The token index is a numeric value that reveals the part of the PHP language that was found. It’s important to note that these values are automatically generated based on PHP’s underlying parser infrastructure. This means that the numeric value of a token may change between two PHP versions. This also means that code should never rely directly on the original T_* values but reference the constants instead.
List of tokens: http://www.php.net/manual/en/tokens.php
The token_name($value) function returns the symbolic name (T_*) for the given numeric value. This gives us the information we need to continue.
The parser simply looks for the various strings (add_action, do_action, etc.) and then processes them accordingly.
 => 368 (T_OPEN_TAG)  => <?php  => 367 (T_DOC_COMMENT)  => /** * Front to the WordPress application. This file doesn't do anything, but loads * wp-blog-header.php which does and tells WordPress to load the theme. * * @package WordPress */  => 2  => 371 (T_WHITESPACE)  =>  => 7  => 367 (T_DOC_COMMENT)  => /** * Tells WordPress to load the WordPress theme and output it. * * @var bool */  => 9  => 371 (T_WHITESPACE)  =>  => 13  => 307 (T_STRING)  => define  => 14  => 315 (T_CONSTANT_ENCAPSED_STRING)  => 'WP_USE_THEMES'  => 14
An example of raw tokens.
Each hook type we are looking for has a separate processor due to the various syntaxes, but they behave more or less the same putting found information into two arrays, one indexed by the hook name and another indexed by filename and line number.
There are actually two levels of processors, a generic one and a hook-specific one. The hook-specific processors call the generic one to get call parameters and docblocks.
Once the large data arrays are gathered, the output is gathered and sent out. The data is in a standard format, so the processors simply iterate the arrays and assemble the correct information.
We have output for HTML, JSON, and plain text. Other output formats are easy to generate...
[wp_head] => Array  => Array [token] => Array  => 307  => add_action  => 47 [file] => Array [dir] => ../wp [file] => wp-activate.php [fullpath] => ../wp/wp-activate.php [friendly_name] => wp-activate.php [hook] => wp_head [function_to_add] => 'do_activate_header' [priority] => 10 (default) [arguments] => 1 (default)  => Array [token] => Array  => 307  => add_action  => 65 [file] => Array [dir] => ../wp [file] => wp-activate.php [fullpath] => ../wp/wp-activate.php [friendly_name] => wp-activate.php [hook] => wp_head [function_to_add] => 'wpmu_activate_stylesheet' [priority] => 10 (default) [arguments] => 1 (default)
An example of a wp_head data structure.