Это немного более сложный пример, который, помимо данных из массива $wp_filter
, покажет путь к файлу, к которому прикреплен хук, а также строку в коде, где определена функция.
Чтобы получить базовый список функций, подключенных к определенному действию (или фильтру), достаточно выбрать элементы из массива фильтра, но так как функции могут быть присоединены различными способами (как метод класса илизакрытие), этот список будет содержать тонну релевантных данных, которые включают объекты, представленные в виде строки.В этом примере будут отображаться только соответствующие данные в порядке приоритета:
- имя функции (в зависимости от синтаксиса обратных вызовов):
- обратный вызов функции:
'function_name'
- метод объекта:
array( $object, 'function_name' )
- метод статического класса:
array( 'class_name', 'function_name' )
и 'class_name::function_name'
- замыкание:
function() {}
- метод относительного статического класса:
array( 'class_name', 'parent::function_name' )
- допустимые аргументы
- имя файла
- начальная строка
- id
- приоритет
function list_hooks( $hook = '' ) {
global $wp_filter;
if ( isset( $wp_filter[$hook]->callbacks ) ) {
array_walk( $wp_filter[$hook]->callbacks, function( $callbacks, $priority ) use ( &$hooks ) {
foreach ( $callbacks as $id => $callback )
$hooks[] = array_merge( [ 'id' => $id, 'priority' => $priority ], $callback );
});
} else {
return [];
}
foreach( $hooks as &$item ) {
// skip if callback does not exist
if ( !is_callable( $item['function'] ) ) continue;
// function name as string or static class method eg. 'Foo::Bar'
if ( is_string( $item['function'] ) ) {
$ref = strpos( $item['function'], '::' ) ? new ReflectionClass( strstr( $item['function'], '::', true ) ) : new ReflectionFunction( $item['function'] );
$item['file'] = $ref->getFileName();
$item['line'] = get_class( $ref ) == 'ReflectionFunction'
? $ref->getStartLine()
: $ref->getMethod( substr( $item['function'], strpos( $item['function'], '::' ) + 2 ) )->getStartLine();
// array( object, method ), array( string object, method ), array( string object, string 'parent::method' )
} elseif ( is_array( $item['function'] ) ) {
$ref = new ReflectionClass( $item['function'][0] );
// $item['function'][0] is a reference to existing object
$item['function'] = array(
is_object( $item['function'][0] ) ? get_class( $item['function'][0] ) : $item['function'][0],
$item['function'][1]
);
$item['file'] = $ref->getFileName();
$item['line'] = strpos( $item['function'][1], '::' )
? $ref->getParentClass()->getMethod( substr( $item['function'][1], strpos( $item['function'][1], '::' ) + 2 ) )->getStartLine()
: $ref->getMethod( $item['function'][1] )->getStartLine();
// closures
} elseif ( is_callable( $item['function'] ) ) {
$ref = new ReflectionFunction( $item['function'] );
$item['function'] = get_class( $item['function'] );
$item['file'] = $ref->getFileName();
$item['line'] = $ref->getStartLine();
}
}
return $hooks;
}
Поскольку хуки можно добавлять и удалять в течение всего времени выполнения, выходные данные зависят от того, в какой момент вызывается функция (wp_footer
действие - хорошее место для получения полного списка)
print_r
пример для the_content
фильтра:
Array
(
[0] => Array
(
[id] => 000000004c8a4a660000000011808a14run_shortcode
[priority] => 8
[function] => Array
(
[0] => WP_Embed
[1] => run_shortcode
)
[accepted_args] => 1
[file] => C:\xampp\htdocs\wordpress\wp-includes\class-wp-embed.php
[line] => 58
)
[1] => Array
(
[id] => wptexturize
[priority] => 10
[function] => wptexturize
[accepted_args] => 1
[file] => C:\xampp\htdocs\wordpress\wp-includes\formatting.php
[line] => 41
)
[2] => Array
(
[id] => 0000000006c5dc6d0000000064b1bc8e
[priority] => 10
[function] => Closure
[accepted_args] => 1
[file] => C:\xampp\htdocs\wordpress\wp-content\plugins\plugin\plugin.php
[line] => 16
)
.....
Редактировать: 2017-05-05
- адаптировано для
WP_Hook
класс - добавлен приоритет
- исправлено: ошибка возникает, если обратного вызова не существует, хотя WordPress также выдает предупреждение для этого
- исправлено: перехват с тем же идентификатором, но с разницейприоритет приоритета заменяет предыдущий