Что такое хук в WordPress? Полезные советы по работе с хуками в WordPress
Если вы плохо знакомы с хуками, эта статья поможет вам. Приведенные в статье примеры взяты из ядра WordPress, а также из собственного многолетнего опыта работы разработчиком плагинов.

Хуки WordPress - это функция, которая позволяет расширять возможности плагины и темы без риска их сломать.
- Что такое хук?
- Элементы процедуры хука
- Хук (существительное)
- Действия и фильтры
- Хук (глагол)
- Вы уже используете эти хуки
- Уроки использования the_content
- Параметры в процедуре хука
- Имена хуков ($teg)
- Префиксы имен хуков
- Динамические имена хуков
- Магический "all"
- Имена функций
- Использование PHP функций по умолчанию
- Приоритеты
- Проверка выполнения действия
- Проверка использования фильтра
- Аргументы
- Сложности с количеством аргументов
- Удаление действий и фильтров
- Как найти хук?
- Отладка хуков
- Использование error_log()
- Использование HOOK API
- Использование плагинов
- Приступаем к работе
Что такое хук?
Хук «do» называется «действием». В любом месте, где определено действие, можно выполнить собственный код. Вот некоторые примеры:
- отправить электронное письмо автору после публикации записи;
- загрузить пользовательский скрипт в футере страницы;
- добавить инструкции над формой входа.
Хук «customize» называется «фильтром». Фильтр позволяет изменять или настраивать значение и возвращать его в новой форме. Вот некоторые примеры:
- вывод заголовков записей заглавными буквами;
- прикрепление ссылки к связанным записям ниже основного контента;
- изменение параметра, который извлекается из базы данных.
Для фильтра важна не только позиция, но и возвращаемые значения. WordPress имеет фильтр почти для каждого значения, которое обрабатывает.
Элементы процедуры хука
Используем в качестве примера действия хук wp_head, а в качестве примера фильтра хук the_content.
Хук (существительное)
Сам хук - это указание того, когда и где происходит магия. Представьте себе, что это крюк, который альпинист вбил в поверхность скалы. Крюк имеет определенную позицию. Если другие альпинисты захотят двигаться в этом направлении, они могут использовать его.
Хуки действий вызываются с помощью функции do_action:
do_action('wp_head');
Хуки вызываются с помощью apply_filters():
$content=apply_filters('the_content',$content);
Как видите, нам нужно перехватить данные из фильтра.
Действия и фильтры
Следующий элемент в процедуре хука - это действие или фильтр. Это функция, которую вы определяете, чтобы сделать или отфильтровать что-то. Это альпинист, который готов использовать любой крюк, чтобы взобраться немного выше.
Действие, которое запускается в wp_head- это noindex().
functionnoindex(){
// Если блог не является публичным, указать роботам проходить мимо.
if('0'==get_option('blog_public'))
wp_no_robots();
}
Хук проверяет, отключена ли настройка видимости для поисковых систем. Если это так, wp_no_robots() добавляет мета тег robots, указывающий поисковым системам не индексировать сайт.
Примером фильтра для the_content является wpautop(). Он отвечает за перенос абзацев в теге <p> и использование тега <br /> для разрывов строк.
functionwpautop($pee,$br=true){
// …
return$pee;
}
В отличие от действия, функции фильтра требуется хотя бы один аргумент. Он должен быть возвращен.
Хук (глагол)
В процедуре хука WordPress нужно указать, для чего именно предназначен хук. Это означает, что мы должны привязать функцию (глагол) к крюку (существительному). Это делается с помощью функции, которая часто неправильно называется «хуком».
Для хука wp_head и действия noindex() связь устанавливается с помощью этой строки кода:
add_action('wp_head','noindex',1);
Третий параметр является приоритетом. Мы рассмотрим его ниже.
Включение wpautop() в the_contentо осуществляется с помощью этой строки:
add_filter('the_content','wpautop');
Это основные принципы процедуры хука. В следующих разделах мы рассмотрим их более подробно.
Вы уже используете эти хуки
Даже если вы «просто» изменяете тему или добавляете код в файл functions.php, вы уже используете действия и фильтры.
WP_HEAD
Рассмотрим раздел заголовка темы Twenty Fifteen, который можно найти в файле wp-content/themes/twentyfifteen/header.php.
<!DOCTYPE html>
<html <?phplanguage_attributes();?>class="no-js">
<head>
<metacharset="<?phpbloginfo('charset');?>">
<metaname="viewport"content="width=device-width">
<linkrel="profile"href="http://gmpg.org/xfn/11">
<linkrel="pingback"href="<?phpbloginfo('pingback_url');?>">
<!--[iflt IE 9]>
<script src="<?phpechoesc_url(get_template_directory_uri());?>/js/html5.js"></script>
<![endif]-->
<?phpwp_head();?>
</head>
Между открывающимся и закрывающимся тегами <head> размещается не так уж много кода, но просмотрите исходный код страницы в браузере. Вы увидите там различные мета элементы, включая тег <title>.
Элементы, которые могут отсутствовать в файле header.php, добавляются функцией wp_head(). Если вы используете среду разработки, просмотрите ее содержимое.
/**
* Запуск действия wp_head
*
* @since 1.2.0
*/
functionwp_head(){
/**
* Выводим через front-end скрипт или данные в теге head.
*
* @since 1.5.0
*/
do_action('wp_head');
}
Единственное, что делает функция wp_head(), это выводит хук wp_head. Это означает, что тема может использовать do_action(‘wp_head’), вместо wp_head ().
Этот хук уже используется ядром. Вот некоторые действия, которые WordPress подключает к этому хуку по умолчанию:
add_action('wp_head','_wp_render_title_tag',1);
add_action('wp_head','wp_enqueue_scripts',1);
add_action('wp_head','feed_links',2);
add_action('wp_head','feed_links_extra',3);
add_action('wp_head','rsd_link');
add_action('wp_head','wlwmanifest_link');
add_action('wp_head','adjacent_posts_rel_link_wp_head',10,0);
add_action('wp_head','locale_stylesheet');
add_action('wp_head','noindex',1);
add_action('wp_head','print_emoji_detection_script',7);
add_action('wp_head','wp_print_styles',8);
add_action('wp_head','wp_print_head_scripts',9);
add_action('wp_head','wp_generator');
add_action('wp_head','rel_canonical');
add_action('wp_head','wp_shortlink_wp_head',10,0);
add_action('wp_head','wp_site_icon',99);
Среди них - действие noindex(), а также (начиная с версии WordPress 4.1) вызов _wp_render_title_tag(), который генерирует тег title.
The content
Пример хука фильтра, который вы использовали, даже не зная об этом - the_content.
Он скрыт за функцией the_content(), которая используется для вывода содержимого записи или страницы. Она содержит вызов хука the_content.
functionthe_content($more_link_text=null,$strip_teaser=false){
$content=get_the_content($more_link_text,$strip_teaser);
// …
$content=apply_filters('the_content',$content);
$content=str_replace(']]>',']]>',$content);
echo$content;
}
По умолчанию к функции the_content уже подключено несколько фильтров.
add_filter('the_content','wptexturize');
add_filter('the_content','convert_smilies');
add_filter('the_content','convert_chars');
add_filter('the_content','wpautop');
add_filter('the_content','shortcode_unautop');
add_filter('the_content','prepend_attachment');
Эти фильтры отвечают за формат и ряд специальных символов в тексте. Они также широко используется плагинами для присоединения таких элементов, как иконки социальных сетей или связанных записей.
Уроки использования the_content
Вот два примера того, как неправильное использование хука приводит к сбою в работе функции.
Тело функции the_content() также содержит вызов get_the_content(). Я видел, как второй использовался вместо первого в нескольких темах. Но таким образом сам хук отключается, и многие функции не будут работать.
Если вы подключаетесь к the_content, то имейте в виду, что он используется не только на страницах контента, но и на страницах списков. Например, в архивах, а также на главной странице.
Параметры в процедуре хука
Основные параметры, которые нужны - это имя хука, имя функции, приоритет и аргументы, которые ей передаются.
Вот как выглядит вызов add_filter:
add_filter($tag,$function,$priority,$accepted_args);
Имена хуков ($teg)
Вы не сможете ничего сделать с именами хуков, которые используются в ядре WordPress, плагинах или темах оформления. Но при задании собственных имен нужно придерживаться нескольких принципов.
Имя действия должно включать в себя место, а фильтр-место и значение, которое будет изменено.
В качестве примеров действий можно привести wp_head и wp_footer, которые называются в соответствии с местом их расположения. Также часто используются префиксы или суффиксы. Например: before, pre, begin, after и end.
Функция wp_delete_post(), которая отвечает за удаление записи, включает в себя следующие хуки:
- before_delete_post;
- delete_post;
- deleted_post;
- after_delete_post.
Префиксы имен хуков
Помимо позиции и значения нужно задать префикс хука префикса. Например:
- wpseo_ от Yoast SEO;
- genesis_ от фреймворка Genesis;
- advanced_ads_ от моего плагина Advanced Ads.
Это предотвращает конфликты с хуками в других плагинах или темах оформления.
Динамические имена хуков
Предположим, что в плагине есть много параметров, и вы хотите, чтобы другие разработчики могли использовать фильтр для каждого из них. Для этого нужно вызывать apply_filters() для каждого параметра. Также можно использовать динамическое имя хука, как это делает WordPress в функции get_options().
Данная функция включает в себя следующие хуки:
- 'pre_option_' . $option;
- 'default_option_' . $option;
- 'option_' . $option.
Зная это, вы сможете подключиться к option_blogname или option_blogdescription, чтобы динамически изменять название или описание блога.
Магический "all"
При вызове add_action() и add_filter() в качестве имени хука можно использовать специальный тег. Благодаря чему связанная функция будет использоваться для каждого хука.
Имена функций
При вызове простой функции добавляйте префикс. Это предотвратит конфликты с другими вспомогательными функциями, которые идентифицируют его.
На форумах можно встретить имена функций, начинающиеся с my_. Измените этот префикс на свой.
add_filter('the_content','bestpluginever_capitalize_all_words');
Также возможно подключение статичной функции в классе:
add_filter('the_content',array('bestpluginever','capitalize_all_words'));
Ее вызов в экземпляре этого класса будет выглядеть следующим образом:
add_filter('the_content',array($bestpluginever,'capitalize_all_words'));
Также можно вызвать метод в экземпляре того же класса, например:
add_filter('the_content',array($this,'capitalize_all_words'));
Также убедитесь, что функции являются public.
Использование PHP функций по умолчанию
В определенных случаях не нужно создавать собственную функцию. Эта процедура хука преобразует в заглавную каждую первую букву заголовка записи:
functionbestpluginever_capitalize_title($title){
returnucwords($title);
}
add_filter('the_title','bestpluginever_capitalize_title');
Поскольку ucwords() является стандартной функцией PHP, которая принимает и возвращает значение, ее можно сократить до одной строки:
add_filter('the_title','ucwords');
Приоритеты
Третий параметр в add_action() и add_filter()- это приоритет. Он устанавливает порядок, в котором вызываются функции, связанные с хуком.
Этот параметр является необязательным и по умолчанию равен 10, если не определен явно. Несколько функций с одинаковым приоритетом будут вызываться в том порядке, в котором они были зарегистрированы в хуке.
Плагин Advanced Ads использует the_content при вставке рекламных объявлений до или после контента. Ее третий параметр определяет, вставляется ли сначала рекламное объявление или другой контент. Чтобы избежать обращений за поддержкой относительно «неправильного» порядка элементов, я предоставил пользователям возможность выбирать приоритет фильтра в качестве опции.
Проверка выполнения действия
Чтобы проверить, выполнено ли конкретное действие, можно использовать did_action().
Функция _wp_render_title_tag была подключена к wp_head. Это пример того, как ядро Wordpress проверяет, что тег title действительно создан только тут.
function_wp_render_title_tag(){
if(!current_theme_supports('title-tag')){
return;
}
// Это может работать только внутри wp_head.
if(!did_action('wp_head')&&!doing_action('wp_head')){
return;
}
echo'<title>'.wp_title('|',false,'right')."</title>n";
}
did_action($hook) возвращает информацию о том, сколько раз было выполнено действие, включая текущий вызов. Функция вернет 1, если _wp_render_title_tag() запускается в wp_head. do_action('wp_head') проверяет, находимся ли мы сейчас в действии wp_head. Фактически, приведенный выше код - это двойная проверка. Из-за этого он будет удален из WordPress 4.4.0.
Функция do_action() проверяет, действительно ли происходит действие.
Проверка использования фильтра
Для фильтров did_action() и do_action() нет псевдонимов. Вместо них нужно использовать has_filter($hook, $function). Когда указан только $hook, будет возвращено значение true, если какая-либо функция зарегистрирована для hook. Значение false - в противном случае.
Если также передана функция $function, то будет возвращен приоритет этой функции, или значение false, если эта функция не подключена к хуку.
При добавлении рекламных объявлений после определенного абзаца плагин Advanced Ads должен убедиться, что wpautop() вызывается до того, как будет применена пользовательская функция фильтра.
$wpautop_priority=has_filter('the_content','wpautop');
if($wpautop_priority&&$advads_content_injection_priority()<$wpautop_priority){
$content=wpautop($content);
}
С помощью этого фрагмента кода я проверяю, является ли приоритет wpautop() выше, чем приоритет функции включения рекламных объявлений. Получается, что параграфы еще не установлены, и это указывает плагину сначала создавать их.
Аргументы
Рассмотрим хук delete_term, который запускается после того, как термин удален из базы данных.
do_action('delete_term',$term,$tt_id,$taxonomy,$deleted_term);
При использовании функции add_action() или add_filter() четвертый параметр - это количество аргументов, которое ожидает функция действия или фильтра.
В нашем случае функция- хук может использовать эти четыре аргумента. Но это не обязательно. Что подтверждается взаимосвязью, реализованной в ядре:
add_action('delete_term','_wp_delete_tax_menu_item',10,3);
Действие использует только первые три аргумента, а не $deleted_term.
function_wp_delete_tax_menu_item($object_id=0,$tt_id,$taxonomy){
// …
}
Сложности с количеством аргументов
Указанное число аргументов должно соответствовать количеству, которое использует функция. Но это правило необязательное, если аргументов нет или он только один.
Если функции требуется больше аргументов, вам придется их установить, иначе вы получите сообщение об ошибке. Если вы их установили, также необходимо будет установить приоритет, который во многих случаях является необязательным.
Удаление действий и фильтров
Удаление из хука действия или фильтра не является чем-то необычным. Популярным примером было удаление emojis из WordPress 4.2.
Весь плагин Disable Emojis можно свести к приведенному ниже коду:
functiondisable_emojis(){
remove_action('wp_head','print_emoji_detection_script',7);
remove_action('admin_print_scripts','print_emoji_detection_script');
remove_action('wp_print_styles','print_emoji_styles');
remove_action('admin_print_styles','print_emoji_styles');
remove_filter('the_content_feed','wp_staticize_emoji');
remove_filter('comment_text_rss','wp_staticize_emoji');
remove_filter('wp_mail','wp_staticize_emoji_for_email');
}
add_action('init','disable_emojis');
Также существуют плагины, которые отключают функцию wpautop(). А ведь этоможно сделать с помощью всего одной строкикода в файле functions.php.
remove_filter('the_content','wpautop');
Функции remove_action() и remove_filter() принимают три аргумента:
- Хук;
- Функция;
- Приоритет.
Все они должны соответствовать значениям из add_action() и add_filter(). Сложность заключается в том, что хук будет удален только в том случае, если он уже добавлен.
Как найти хук?
Чтобы найти хук, нужно просто знать, что бы вы ни хотели изменить или добавить. Чтобы приступить к работе, можно просто изучить функции, которые уже используются в текущем коде.
Еще одним ресурсом, который можно использовать, является страница API плагинов. На ней перечислены важные функции и другая полезная информация.
Отладка хуков
Чтобы отлаживать хуки, создайте список всех подключенных действий и фильтров.
Использование error_log()
Для отладки фильтров я предпочитаю использовать error_log() в сочетании с DEBUG_LOG. При этом вывод записывается в файл debug.log, но не отображается через front-end.
functionexample_content_filter($content){
$option=get_option('add_haha');
error_log($option);
if($option===true){
$content.='HAHA<br/>'.$content;
}
return$content;
}
add_filter('the_content','example_content_filter');
В приведенном выше сценарии я добавляю к контенту строку HAHA. Но только если параметр возвращает значение true. Если это не работает, можно использовать error_log($ option).
Использование HOOK API
Другой способ отладки хуков - использование функций, упомянутых выше. Например, doing_action() или did_action().
В этот перечень также можно добавить current_filter(). Вы можете использовать ее для отображения имени текущего хука:
functionmy_filter(){
echocurrent_filter();// 'the_content'
}
add_filter('the_content','my_filter');
Если вы хотите увидеть, где это используется в ядре, посмотрите capital_P_dangit(). Готов поспорить, что большинство из вас не знали, что такой фильтр вообще существует.
Использование плагинов
Кроме этого существуют плагины для отладки, которыедают возможность увидеть список всех хуков и подключенных функций. Лично я использую Debug Objects.
Приступаем к работе
Надеюсь, что теперь выбудете лучше понимать решения, которые приводятся на разных форумах.