10 полезных приемов по работе с hook’ами в WordPress

10 полезных приемов по работе с hook'ами в WordPress
Механизм hook'ов (перехватчиков событий) — крайне полезная вещь в WordPress. Они позволяют "подцепить" к некоторым функциям свои собственные, а значит — откорректировать функции WordPress без редактирования базовых файлов. В этой статье мы собрали 10 действительно полезных hook'ов вместе с примерами и объяснениями кода.

Что такое Hook?

Чтобы добиться в блоге WordPress определенного эффекта, нужно изменить способ его работы. В таких случаях зачастую вносятся модификации в файлы, которые разработчики WordPress именуют базовыми — необходимыми для корректной работы WordPress.

Редактирование базовых файлов всегда чревато неприятностями, включая появление брешей в безопасности. Кроме того, после обновления WordPress все изменения будут утеряны.
И все же некоторые функции разработчикам WordPress приходится переписывать, поэтому и появились программные надстройки Plugin API.

Hook'и — один из основных "строительных материалов" для программных модулей WordPress. Практически все модули переписывают базовые функции WordPress с помощью hook`ов.

Как использовать hook'и в блоге WordPress

Все hook`и прописываются в файле "functions.php" (если только речь не идет о создании программного модуля). Данный файл можно найти в папке "wp-content/themes/yourtheme".

Как мы уже говорили, hook`и-перехватчики переопределяют одни функции на другие. Так, например, создав собственную функцию, можно подключить ее к одной из базовых функций WordPress.

add_action ( 'publish_post', 'myCustomFunction' );

В нашем случае мы переопределяем собственную функцию на программную функцию публикации записей "publish-post". Каждый раз при выполнении "publish-post" WordPress будет выполнять и связанную с ней функцию.

Само собой, любые hook`и можно удалить посредством функции "remove_action()".

remove_action ( 'publish_post', 'myCustomFunction' );

1. Отключение автоматического форматирования WordPress

Отключение автоматического форматирования WordPress
Проблема. Возможно, вы заметили, что по умолчанию WordPress заменяет прямые кавычки “парными” и выполняет некоторые другие незначительные действия по форматированию при отображении записи.

Для публикующих нормальное наполнение такая опция удобна, но любого, кто в собственном блоге обсуждает код, это серьезно раздражает: при вставке в текстовый редактор парные кавычки возвращают синтаксическую ошибку.

Решение. Достаточно вставить в файл "functions.php" представленный ниже код:

function my_formatter($content) {
$new_content = '';
$pattern_full = '{(\[raw\].*?\[/raw\])}is';
$pattern_contents = '{\[raw\](.*?)\[/raw\]}is';
$pieces = preg_split($pattern_full, $content, -1, PREG_SPLIT_DELIM_CAPTURE);

foreach ($pieces as $piece) {
if (preg_match($pattern_contents, $piece, $matches)) {
$new_content .= $matches[1];
} else {
$new_content .= wptexturize(wpautop($piece));
}
}

return $new_content;
}

remove_filter('the_content', 'wpautop');
remove_filter('the_content', 'wptexturize');

add_filter('the_content', 'my_formatter', 99);

После этого можно использовать в записях сокращение "[raw]".

[raw]Этот текст не будет автоматически отформатирован.[/raw]

Анализ кода. Первым шагом мы создаем функцию, с помощью обычного выражения ищущую в наполнении записей сокращение "[raw]".

После привязываем функцию "my_formatter()" к программной функции "the_content()". Соответственно, каждый раз при обращении к функции "the_content()" автоматически будет вызываться и "my_formatter()".

Для удаления автоматического форматирования воспользуемся функцией "remove_filter()", позволяющей избавиться от hook'а для конкретной функции.

2. Распознавание браузера посетителя с помощью hook'а

Распознавание браузера посетителя с помощью hook'а
Проблема. Кросс-браузерная совместимость — едва ли не самая распространенная проблема веб-разработчиков. Возможность распознавать браузеры посетителей веб-сайта снимет массу вопросов — если после распознавания создать собственный класс, заключенный в тэг "body". Хотя об этом знают немногие, в WordPress уже реализована возможность распознавания браузеров плюс предусмотрено несколько глобальных переменных.

Решение. Ничего сложного: вставьте представленный ниже код в файл "functions.php". Теперь осталось его просто сохранить!

<?php
add_filter('body_class','browser_body_class');
function browser_body_class($classes) {
global $is_lynx, $is_gecko, $is_IE, $is_opera, $is_NS4, $is_safari, $is_chrome, $is_iphone;

if($is_lynx) $classes[] = 'lynx';
elseif($is_gecko) $classes[] = 'gecko';
elseif($is_opera) $classes[] = 'opera';
elseif($is_NS4) $classes[] = 'ns4';
elseif($is_safari) $classes[] = 'safari';
elseif($is_chrome) $classes[] = 'chrome';
elseif($is_IE) $classes[] = 'ie';
else $classes[] = 'unknown';

if($is_iphone) $classes[] = 'iphone';
return $classes;
}
?>

После сохранения файла функция будет автоматически добавлять класс таблиц стилей к тэгу "body", как в приведенном ниже примере:

<body class="home blog logged-in safari">

Анализ кода. Глобальные переменные WordPress возвращают "true" при использовании посетителем определенного браузера. Если это Google Chrome, значение "true" вернет переменная "$is_chrome". Поэтому мы создаем функцию "browser_body_class()", возвращающую название браузера пользователя. После этого достаточно переопределить ее на программную функцию "body_class()".

3. Распознавание текста в редакторе TinyMCE

Распознавание текста в редакторе TinyMCE
Проблема. Многие блоггеры почти во всех записях используют один и тот же стиль. Записи в моем собственном блоге WpRecipes.com всегда выводятся одинаково: часть текста, часть кода, потом еще текст.
Возможно, стоит сэкономить время, сделав так, что текст по умолчанию будет отображать tinyMCE (визуальный редактор WordPress).

Решение. И снова на помощь приходят hook'и. Откройте файл "functions.php", вставьте код — и предоставьте все остальное им!

<?php
add_filter('default_content', 'my_editor_content');

function my_editor_content( $content ) {
$content = "If you enjoyed this post, make sure to subscribe to my rss feed.";
return $content;
}
?>

Анализ кода. Несмотря на широкие возможности кода, сам метод достаточно просто. Просто создайте функцию, которая возвращает нужный текст (в нашем примере простой текст с предложением о подписке на RSS-ленту блога). Теперь достаточно "подцепить" ее к программной функции "default_content()".

4. Автоматическая вставка наполнения после каждой записи

Автоматическая вставка наполнения после каждой записи
Проблема. Для вставки после записи текста, изображений или рекламы в блогах чаще всего используется шаблон "single.php". Само собой, для этого можно открыть "single.php" и после функции "the_content()" внести нужный текст. Но что если текст не отображается в RSS-ленте? Решить проблему помогут hook'и и описанный ниже прием.

Решение. И снова просто вставьте код в относящийся к нужной теме файл "functions.php". Вот и все.

function insertFootNote($content) {
if(!is_feed() && !is_home()) {
$content.= "<div class='subscribe'>";
$content.= "<h4>Enjoyed this article?</h4>";
$content.= "<p>Subscribe to our  <a href='http://feeds2.feedburner.com/WpRecipes'>RSS feed</a> and never miss a recipe!</p>";
$content.= "</div>";
}
return $content;
}
add_filter ('the_content', 'insertFootNote');

Анализ кода. Задача функции "insertFootNote()" предельно ясна: она сцепляет определенный текст с переменной "$content", включающей содержимое записи.

Затем наша функция "insertFootNote()" переопределяется на функцию "the_content()", автоматически вызываясь каждый раз при обращении к "the_content". Принцип работы с данной функцией аналогичен набору текста в конце каждой записи.

Обратите внимание на условие "(!is_feed)" в строке 2, препятствующее вставке текста в RSS-ленту. Чтобы снять это ограничение, замените строку 2 на следующий код:

if (!is_home()) {

5. Отключение сообщения "Please Update Now" на консоли WordPress

Отключение сообщения "Please Update Now" на консоли WordPress
Проблема. При выходе новой версии WordPress консоль автоматически дает об этом знать, выводя сообщение в верхнюю часть интерфейса администратора. Вещь это, конечно, нужная, ведь для блога обновления — это новые функции и доработки по безопасности. Но если блог делается под заказ, сообщения об обновлениях уместны далеко не всегда.

Решение. В файл "functions.php" достаточно добавить четыре строки кода.

if (!current_user_can('edit_users')) {
add_action( 'init', create_function( '$a', "remove_action( 'init', 'wp_version_check' );" ), 2 );
add_filter( 'pre_option_update_core', create_function( '$a', "return null;" ) );
}

После сохранения файла "functions.php" сообщения на консоли вы больше не увидите.

Анализ кода. Первым делом нужно убедиться, что у текущего пользователя есть права администратора, достаточные для обновления WordPress. После этого создаем два hook'а, переписывающие автоматическую проверку обновлений с выводом сообщений.

6. Отключение автосохранения записей в WordPress

Отключение автосохранения записей в WordPress
Проблема. При наборе записи через консоль WordPress периодически сохраняет ее наполнение. Это полезная функция, но иногда возникает потребность ее отключить.

Решение. Для отключения автосохранения в WordPress откройте файл "functions.php" и вставьте следующую функцию:

function disableAutoSave(){
wp_deregister_script('autosave');
}
add_action( 'wp_print_scripts', 'disableAutoSave' );

Анализ кода. И вновь ничего сложного. Мы просто создаем действие (в строке 4) и переопределяем созданную в строке 1 функцию "disableAutoSave()" на программную "wp_print_scripts()".

В результате наша функция "disableAutoSave()" вызывается при каждом выполнении программой "wp_print_scripts()". Тем самым мы отключаем автосохранение в WordPress.

7. Борьба с дублированием наполнения на странице комментариев

Борьба с дублированием наполнения на странице комментариев
Проблема. Дублирование наполнения — SEO-проблема многих сайтов. Она может стать актуальной и для вашего блога, если только не воспользоваться некоторыми хитростями.

Появившийся в версии 2.7 постраничный вывод комментариев (paged comments) стал ценным дополнением к WordPress, поскольку теперь блоггеры получили возможность разбивать массу комментариев на несколько страниц. Единственная проблема при этом, как уже упоминалось выше, — риск дублирования наполнения.

Чтобы избежать дублирования в постраничных комментариях, воспользуемся новым атрибутом rel="canonical".

Решение. Просто вставьте представленный ниже код в файл "function.php".

function canonical_for_comments() {
global $cpage, $post;
if ( $cpage > 1 ) :
echo "\n";
echo "<link rel='canonical' href='";
echo get_permalink( $post->ID );
echo "' />\n";
endif;
}

add_action( 'wp_head', 'canonical_for_comments' );

Анализ кода. Первым шагом создаем функцию, добавляющую к комментариям страниц (за исключением страницы 1) атрибут rel="canonical". После переориентируем ее на программную функцию "wp_head()". Только и всего!

8. Превращение записи или страницы в PHP-переменную

Превращение записи или страницы в PHP-переменную
Проблема. Возможность превратить текущую запись или страницу в PHP-переменную определенно полезна. Среди прочего можно, например, заменить часть наполнения с помощью PHP-функции "str_replace()".

Решение. И снова ничего сложного. Просто вставьте код в файл "functions.php".

function callback($buffer) {
//модифицируем буфер и возвращаем обновленный код
return $buffer;
}

function buffer_start() {
ob_start("callback");
}

function buffer_end() {
ob_end_flush();
}

add_action('wp_head', 'buffer_start');
add_action('wp_footer', 'buffer_end');

Анализ кода. Для этого приема нам понадобятся три функции:
- callback(): данная функция возвращает страницу целиком в виде переменной "$buffer". Перед этим можно модифицировать ее с помощью стандартных выражений.
- buffer_start(): данная функция просто запускает буфер, переопределяясь на программную функцию "wp_head()".
- buffer_end(): данная функция очищает буфер, переопределяясь на программную функцию "wp_footer()".
Как только наша функция будет готова, просто свяжем ее с программными функциями WordPress.

9. Планирование событий с помощью Cron и hook'ов

Планирование событий с помощью Cron и hook'ов
Проблема. Как вы, возможно, знаете, в WordPress есть возможность планировать события, например, публикуя записи в предварительно заданные дни и часы. С помощью hook'ов и "wp-cron" легко запланировать свои собственные события. В нашем примере блог WordPress раз в час будет отправлять нам электронное сообщение.

Решение. Вставьте блок с приведенным ниже кодом в относящийся к нужной теме файл "functions.php".

if (!wp_next_scheduled('my_task_hook')) {
wp_schedule_event( time(), 'hourly', 'my_task_hook' );
}

add_action( 'my_task_hook', 'my_task_function' );

function my_task_function() {
wp_mail('[email protected]', 'Automatic email', 'Hello, this is an automatically scheduled email from WordPress.');
}

Анализ кода. Первым делом, мы, конечно же, создали функцию, выполняющую нужное действие. В данном примере это функция "my_task_function()", которая просто отправляет сообщение на указанный адрес электронной почты.

Чтобы запланировать событие, воспользуемся функцией "wp_schedule_event()". Последним аргументом должен быть hook, вот почему мы переопределяем функцию "my_task_function()" на "my_task_hook".

10. Вывод всех функций с hook'ами

Вывод всех функций с hook'ами
Проблема. Если что-то пошло не так, при отладке удобно видеть список всех связанных функций.

Решение. Как и в предыдущих примерах, достаточно вставить предложенный код в файл "functions.php". По окончании отладки не забудьте удалить его из файла, иначе служебное сообщение будет появляться и дальше.

function list_hooked_functions($tag=false){
global $wp_filter;
if ($tag) {
$hook[$tag]=$wp_filter[$tag];
if (!is_array($hook[$tag])) {
trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
return;
}
}
else {
$hook=$wp_filter;
ksort($hook);
}
echo '<pre>';
foreach($hook as $tag => $priority){
echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>$tag</strong><br />";
ksort($priority);
foreach($priority as $priority => $function){
echo $priority;
foreach($function as $name => $properties) echo "\t$name<br />";
}
}
echo '</pre>';
return;
}

Сделав это, просто вызовите функцию "list_hooked_functions()", как показано ниже, для вывода на экран всех функций WordPress с hook'ами.

list_hooked_functions();

Анализ кода. Если в качестве аргумента функции не дается имя hook'а, то hook'и выводятся на экран посредством глобальной переменной "$wp_filter". Альтернативный вариант: отображение в списке конкретного hook'а при передаче его имени в качестве атрибута:

list_hooked_functions('wp_head');

Перевод статьи: 10 Useful WordPress Hook Hacks

Рубрика: Настройка WordPress | 22 августа 2009

Предыдущие записи из рубрики `Настройка WordPress`

13 комментариев

Знаток, 23.08.2009 в 11:11

Из всей статьи может пригодиться только 4 пункт. Остальное вообще не представляю где и зачем использовать 🙂

ОтветитьОтветить
coyc, 26.08.2009 в 15:32

на хабре читал 🙂

ОтветитьОтветить
Deimos, 26.08.2009 в 20:32

На хабре не мой перевод, кто то другой перевел, а я и не заметил и мучился сам переводил ;(

ОтветитьОтветить
coyc, 26.08.2009 в 23:19

😀

ОтветитьОтветить
ivan, 04.09.2009 в 21:56

полезные хуки, у меня как новичка, вопрос-есть хук который бы автоматизировал бы одобрение комментов? Akismet стоит.

ОтветитьОтветить
Deimos, 05.09.2009 в 08:36

В смысле автоматизировал одобрение комментариев, Вы хотите чтобы комментарии появлялись без проверки?

ОтветитьОтветить
Алексей, 30.11.2009 в 08:24

Дмитрий, подскажите как реализовать такую идею.

Не секрет, что сайты использующие контент партнерских программ, часто попадают в бан за неуникальность.
Вариант рерайтить описания тех же фильмов, довольно таки накладно, поэтому хочу сделать следующее:

Написать общий текст для всех страничек, размножить генератором, выбрать определеное количество уникальных и добавлять их к описаниям (записям) после функции "the_content()"
Типа

Размноженный текст №1

То есть не ручками после публикации каждой записи, а настроить один раз и на автомате исполнять.
Надеюсь правильно объяснил %)

P.S. Спасибо за блог, много ценной информации.
Ах да, если сочтете, что эта просьба из раздела платных услуг, то я не жадный =)

ОтветитьОтветить
Алексей, 30.11.2009 в 08:42

Исправляю, где
Размноженный текст №1

Читать
[?php if ( is_single(ID) ) { ?]
Размноженный текст №1
[?php }?]

ОтветитьОтветить
Смешной Новостной, 08.07.2011 в 15:31

Здравствуйте. У меня такая проблема. Я хочу, чтобы при публикации записи В ПЕРВЫЙ РАЗ отправлялось сообщение на почту. Вроде всё хорошо. Только отправляется сообщение не только после перехода из статуса "Черновик" в статус "Опубликовано", а ещё и при каждом редактировании/сохранении записи. Может вы подскажете, как справиться с этою бедой. Спасибо.

function sendmessage()
{
global $post;

$to .= 'ID, 'author_email', true) .'>';
$subject = "Your company has published";
$message .= "Congratulations! Your company has been added to the list";
$headers .= "From: Hosting Review \r\n";
@mail($to, $subject, $message, $headers);
}

add_action ('publish_post', 'sendmessage' );

ОтветитьОтветить
kama, 08.07.2011 в 19:05

Смешной Новостной, не знаю точно. Как-то так:

function sendmessage()
{
global $post;
if ( (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || $post->post_status=='draft'  ) return;
...
ОтветитьОтветить
Александр Невский, 23.07.2014 в 21:41

Недавно обратил внимание на огромный размер дампа базы данных, как отключить авто сохранение, вроде понятно. А как теперь почистить саму базу?

ОтветитьОтветить
Страпон, 08.01.2015 в 10:09

Спасибо, делал рекламу на своём адалтнике, нужно было вставить код после каждой новости в WP.

Помогли вот эти Ваши строчки из статьи:
"Для вставки после записи текста, изображений или рекламы в блогах чаще всего используется шаблон "single.php". Само собой, для этого можно открыть "single.php" и после функции "the_content()" внести нужный текст."

Большое спасибо!

ОтветитьОтветить
BUTAMUHbI4, 04.03.2016 в 04:10

Всё никак не могу найти возможность поменять футер на лету.. Благодарю за п.8!

ОтветитьОтветить

Комментировать