Регистрация хуков до запуска системы хуков WordPress
Обычно хуки в WordPress можно использовать только после инициализации ядра, когда глобальный объект $wp_filter уже создан. Однако иногда возникает необходимость создать хук для события раньше — ещё до того, как работает система хуков. Для этого WordPress позволяет определить глобальную переменную $wp_filter заранее.
Как это работает
В WP есть функция WP_Hook::build_preinitialized_hooks(), которая нормализует массив $wp_filter, определённый заранее, и превращает его в полноценные объекты WP_Hook.
Таким образом, вы можете заранее подготовить $GLOBALS['wp_filter'] так, будто хуки уже зарегистрированы. А WP затем в свое время превратит ваш массив в объект WP_Hook и при выполнении хука, отработает ваш коллбэк.
- Хуки обычно регистрируются после запуска WordPress, но можно сделать это раньше, вручную определив
$GLOBALS['wp_filter']. - Для этого используется метод WP_Hook::build_preinitialized_hooks().
- Такой код работает только в
wp-config.phpили раньше. - Подходит для временных решений и низкоуровневых фиксов.
Формат массива $wp_filter
В ключе массива должно быть имя хука, а в значении нужно указать массив коллбэков, сгруппированных по приоритетам:
$filters = [
'wp_fatal_error_handler_enabled' => [
10 => [
[
'accepted_args' => 0,
'function' => function() {
return false;
},
],
],
],
];
Хук wp_fatal_error_handler_enabled вызывается ещё до старта системы хуков. Благодаря этому его можно переопределить уже в wp-config.php.
Пример: редирект с главной страницы на поддомен
Рассмотрим реальный случай. Есть мультисайт: / (английская версия) и /ru/ (русская версия). На время разработки английской версии требовалось временно перенаправлять главную страницу / → /ru/.
Чтобы такое нестандартное поведение было очевидно, а код было легко найти и удалить, он был вынесен в wp-config.php. Но поскольку система хуков там ещё не работает, хук был зарегистрирован через $GLOBALS['wp_filter'].
/// Temp fix for prod site while EN version is under development.
defined( 'WP_CLI' ) || defined( 'DOING_CRON' ) || defined( 'DOING_AJAX' ) || temp_fix_for_multisite_migration_for_prod();
function temp_fix_for_multisite_migration_for_prod() {
$host = 'example.com';
if( $host !== $_SERVER['HTTP_HOST'] ){
return;
}
// ! до изменения REQUEST_URI
if( preg_match( '~^/ru/?$~', $_SERVER['REQUEST_URI'] ) ){
header( "Location: https://$host", true, 307 );
exit;
}
// подмена запроса
if( '/' === $_SERVER['REQUEST_URI'] ){
$_SERVER['REQUEST_URI'] = '/ru/';
}
$temp_ru_home_url_fix = static function( $url, $path, $orig_scheme, $blog_id ){
if( ! $path || '/' === $path ){
$url = preg_replace( '~/ru/?~', '/', $url );
}
return $url;
};
// добавляем хук на событие wp
$GLOBALS['wp_filter'] = [
'wp' => [
0 => [
[
'function' => static fn() => add_filter( 'home_url', $temp_ru_home_url_fix, 99, 4 ),
'accepted_args' => 0,
],
],
],
];
}
Пример: отключение экрана восстановления
$GLOBALS['wp_filter'] = [ 'wp_fatal_error_handler_enabled' => [ 10 => [[ 'function' => static fn() => false, 'accepted_args' => 0, ]], ], ];