Фронтэнд. 15+ хуков для functions.php
Еще одна подборка популярных, полезных и интересных хуков для лицевой части сайта (фронтэнда). Здесь я постарался собрать, проверить и улучшить некоторые интересные и нужные хаки, которые удалось найти в сети. Практически везде были мелкие и крупные ошибки.
Еще подборки хуков:
Изменение картинки на странице входа - wp-login.php
Этот код изменяет страницу входа wp-login.php. Тут можно заменить логотип и ссылку с главной картинки, которая ведет на сайт wordpress.org.
## Изменяет логотип, его ссылку и title атрибут на странице входа
if(1){
// Изменяем картинку (логотип)
// укажите правильную ссылку на картинку.
add_action( 'login_head', 'wp_login_logo_img_url' );
function wp_login_logo_img_url() {
echo '
<style>
.login h1 a{ background-image: url( '. get_template_directory_uri() .'/images/logo.png ) !important; }
</style>';
}
// Изменяем ссылку с логотипа
add_filter( 'login_headerurl', 'wp_login_logo_link_url' );
function wp_login_logo_link_url( $url ){
return home_url();
}
// Изменяем атрибут title у ссылки логотипа
add_filter( 'login_headertitle', 'wp_login_logo_title_attr' );
function wp_login_logo_title_attr( $title ) {
$title = get_bloginfo( 'name' );
return $title;
}
}
Первый хук можно заменить на такой. Тогда картинка логотипа на странице входа будет браться из настройки - картинка заголовка сайта.
## Берет картинку для логотипа на странице входа из установленной в настройках
add_action( 'login_head', 'wp_login_logo_img_url' );
function wp_login_logo_img_url() {
if( function_exists('get_custom_header') ){
$width = get_custom_header()->width;
$height = get_custom_header()->height;
}
else {
$width = HEADER_IMAGE_WIDTH;
$height = HEADER_IMAGE_HEIGHT;
}
echo '
<style>
.login h1 a {
background-image: url('. get_header_image() .') !important;
background-size: '. $width .'px '. $height .'px !important;
width: '. $width .'px !important;
height: '. $height .'px !important;
}
</style>';
}
Редирект на запись при поиске
При поиске на сайте иногда получается так, что найдена всего одна запись. В некоторых случаях удобно сразу делать редирект на эту запись, чтобы пользователю не приходилось кликать для перехода на неё единственную.
// Редирект на запись со страницы поиска, если найдена всего одна запись
add_action('template_redirect', 'single_result');
function single_result(){
if( ! is_search() ) return;
global $wp_query;
if( $wp_query->post_count == 1 ){
wp_redirect( get_permalink( reset($wp_query->posts)->ID ) );
die;
}
}
Google Аналитика и Яндекс метрика (установка)
Код метрики или аналитики можно добавить в файл шаблона header.php напрямую. Но лучше это сделать через хук, чтобы потом программно можно было отключить этот код:
add_action( 'wp_head', 'add_googleanalytics', 99 );
// или, если нужно выводить в подвале
//add_action( 'wp_footer', 'add_googleanalytics', 99 );
function add_googleanalytics(){
?>
// Код счетчика аналитики
// Код счетчика метрики
<?php
}
Увеличить резкость картинок (миниатюр) (только для jpg)
Создаваемым миниатюрам загружаемых изображений как правило не хватает резкости. Иногда они выглядят нормально, но это только иногда... Ну, и резкость миниатюрам еще никогда не мешала 
Код ниже будет работать для всех создаваемых промежуточных размеров. Код рассчитан только на библиотеку GD. Если у вас на сервере Imagick, код ничего не сделает с миниатюрами...
## Повышаем резкость для создаваемых миниатюр (only jpg). Только для GD библиотеки...
add_filter('image_make_intermediate_size', 'sharpen_resized_image_files', 900 );
function sharpen_resized_image_files( $resized_file ){
if( ! function_exists('imagecreatefromstring') )
return $resized_file; // The GD image library is not installed.
// грузим картинку. аналог старой функции wp_load_image()
if(1){
// Увеличиваем размер памяти до максимума.
if( function_exists('wp_raise_memory_limit') ) wp_raise_memory_limit( 'image' );
$image = imagecreatefromstring( file_get_contents($resized_file) );
}
if( ! is_resource($image) )
return $resized_file; // error_loading_image
if( ! $size = @ getimagesize($resized_file) )
return $resized_file; // invalid_image - Could not read image size
list( $orig_w, $orig_h, $orig_type ) = $size;
switch( $orig_type ){
case IMAGETYPE_JPEG:
$matrix = array(
array(-1, -1, -1),
array(-1, 16, -1),
array(-1, -1, -1),
);
$divisor = array_sum(array_map('array_sum', $matrix));
$offset = 0;
imageconvolution( $image, $matrix, $divisor, $offset );
imagejpeg( $image, $resized_file, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
break;
case IMAGETYPE_PNG:
return $resized_file;
case IMAGETYPE_GIF:
return $resized_file;
}
return $resized_file;
}
Что в результате получится:
gzip сжатие
Как работает и в чем фишка? Браузер запрашивает страницу у сервера. Сервер создает HTML код запрошенной страницы, архивирует его (сжимает) и отдает браузеру. Браузер его получает в архивированном виде, разархивирует и показывает нам. В результате архивирования, размер HTML кода при загрузке браузером с сервера уменьшается, например с 500 до 250 КБ.
Такое сжатие можно включить разными способами: в настройках сервера, через файл .htaccess или в PHP. Ниже показан только один способ - включение через один из модулей PHP - это всего один из где-то 6 способов.
Сжатие может быть уже включено:
- автоматически на сервере
- в плагинах страничного кэширования таких как WP Total Cache, WP Super Cache.
Поэтому прежде чем использовать код убедитесь что сжатия еще нет. Для этого посмотрите в HTTP заголовки ответа сервера, там это видно:
- откройте панель-разработчика в браузере Google Chrome (ctrl+shift+i)
- перейдите во вкладку "Сеть"
- перезагрузите страницу в браузере и кликните на первую строку (это запрос HTML кода страницы)
- смотрите в заголовки.
Если сжатие еще не включено, то вставьте код ниже в functions.php темы и проверьте включилось ли оно. Т.к. этот код работает только при включенной PHP библиотеки zlib (она как правило есть на сервере).
if( extension_loaded('zlib') && ini_get('output_handler') != 'ob_gzhandler' ){
add_action('wp', function(){ @ ob_end_clean(); @ ini_set('zlib.output_compression', 'on'); } );
}
Если сжатие не включилось, то поищите в сети другой способ его включить.
Добавим типы записей в поиск
Включать или нет тип записи в поиск устанавливается при регистрации типа записи, в параметре exclude_from_search в register_post_type().
Если тип записи еще не включен в поиск, то альтернативный способ включить его туда - это код ниже. Тут в поиск включается тип записи movie, т.е. теперь при поиске, WP будет искать указанный запрос еще и в типе записи movie.
## Добавляем типы записей в результат поиска
add_action('pre_get_posts', 'get_posts_search_filter');
function get_posts_search_filter( $query ){
if ( ! is_admin() && $query->is_main_query() && $query->is_search ) {
$query->set('post_type', array('post', 'movie') );
}
}
Время генерации страницы
Выведем данные о том сколько запросов было сделано к базе данных для генерации страницы, с какой скоростью было сгенерирована страница и сколько памяти для этого потребовалось.
С версии WP 5.9 появилась функция timer_float(), лучше использовать её:
/**
* Выводит данные о количестве запросов запросов к БД,
* время выполнения скрипта и размер затраченной памяти.
*/
add_filter( 'admin_footer_text', 'kama_wp_usage' );
function kama_wp_usage(): string {
return sprintf(
'SQL: %d. %.3F sec. %s MB',
get_num_queries(),
timer_float(),
round( memory_get_peak_usage()/1024/1024, 2 )
);
}
Для WP 5.8 и ниже:
/**
* Выводит данные о количестве запросов запросов к БД,
* время выполнения скрипта и размер затраченной памяти.
*/
add_filter( 'admin_footer_text', 'wp_usage' ); // в подвале админки
add_filter( 'wp_footer', 'wp_usage' ); // в подвале сайта
function wp_usage(){
echo sprintf(
'SQL: %d за %s sec. %s MB',
get_num_queries(),
timer_stop( 0, 3 ),
round( memory_get_peak_usage()/1024/1024, 2 )
);
}
Ссылка (URL) первой картинки в контенте
Вариант 1:
Код ниже автоматический «вытащит» первую картинку из текущей записи (поста) и вернет готовый <img> код картинки обернутый в ссылку на текущую запись.
В параметре $num, можно указать номер картинки в записи, которую нужно получить. Например, если указать 2, то код получит вторую картинку, а не первую.
/**
* Получает первую или указанную в $num картинку из контента текущей записи в цикле
* и возвращает её в виде `<a><img>` конструкции (картинка = анкор ссылки на текущий пост).
* удобно использовать в качестве миниатюры записи...
*
* @param integer [$num = 1] Номер картинки в тексте которую нужно получить.
* @return string HTML
*/
function get_post_content_image( $num = 1 ){
global $more;
$more = 1;
$content = get_the_content();
$count = substr_count( $content, '<img');
$start = 0;
for( $i=1; $i<=$count && $i<=$num; $i++ ){
$imgBeg = strpos( $content, '<img', $start );
$post = substr( $content, $imgBeg );
$imgEnd = strpos( $post, '>');
$postOutput = substr( $post, 0, $imgEnd+1 );
$postOutput = preg_replace('~(?:width|height)="[0-9]*"~', '', $postOutput );
$image[$i] = $postOutput;
$start = $imgEnd + 1;
}
// картинка есть, выводим
if( isset($image[$num]) && stristr($image[$num], '<img') )
return '<a href="'. get_permalink() .'">'. $image[$num] ."</a>";
$more = 0;
}
Пример использования:
echo get_post_content_image(); // <a href="http://example.com/zapis/"><img class="alignnone size-medium wp-image-126" src="http://example.com/wp-content/uploads/2016/05/asd.jpg" alt=""></a>
Вариант 2:
Смотрите в ответе на вопрос: Как получить URL первой картинки из контента записи?
Какой используется файл шаблона?
Для того чтобы узнать какой файл темы используется для генерации текущей страницы, нужно просто «заглянуть» в глобальную переменю $template.
Этот код выводит путь до файла, который используется как шаблон текущей просматриваемой страницы перед шапкой или в подвале.
add_action('wp_head', 'show_template'); // перед шапкой
// add_action('wp_footer', 'show_template'); // в подвале
function show_template(){
global $template;
echo $template;
}
Добавим тип записи в вывод на архивной странице метки
Допустим, при регистрации типа записи мы указали ему таксономию меток (post_tag) и теперь у нового типа записи тоже есть метки. Теперь нам нужно, чтобы на стандартной странице метки выводились записи и наш новый тип записи.
add_filter('request', 'any_ptype_on_cat');
function any_ptype_on_cat( $request ){
// для меток
if( isset($request['tag']) )
$request['post_type'] = array('post','ярлык_типа_записи');
// для рубрик
if( isset($request['category_name']) )
$request['post_type'] = array('post','ярлык_типа_записи');
return $request;
}
Удалим «прыжок» до «Read More»
Если в тексте записи есть тег <!--more-->, то в цикле записей в рубрике ссылка «Читать дальше» будет вести на страницу записи, а затем пользователя перекидывает к тексту, который идет после этого тега. Чтобы убрать этот «прыжок», используйте такой код:
add_filter('the_content_more_link', 'remove_more_jump_link');
function remove_more_jump_link( $link ){
return preg_replace('~#more-[0-9]+~', '', $link );
}
Код будет работать, только если цитата выводиться через get_the_content() или the_content()
Встраивания (oEmbed) в тексте (в виджете «Текст»)
Вставка объектов в виджете «Текст». Что это значит? Рассмотрим на примере. Допустим, нам нужно чтобы в текстовом виджете, также как и в записи, обрабатывались ссылки из специального белого списка. Например, мы указывает ссылку на видео youtube в отдельной строке и при просмотре она превращается в youtube плеер - ссылка меняется на HTML код налету.
Хак ниже позволяет включить такую «фишку» для текстового виджета. Вставлять код нужно в файл темы functions.php.
После вставки кода мы можешь использовать шорткоды и специальные ссылки. Все это будет обработано.
global $wp_embed; add_filter( 'widget_text', [ $wp_embed, 'run_shortcode' ], 8 ); add_filter( 'widget_text', [ $wp_embed, 'autoembed' ], 8 );
Читайте также: oEmbed в WordPress.
Подключение скриптов/стилей, если в контенте есть шорткод
Подключение и проверка на всех страницах
Этот код показывает, как подключать файл скрипта или стилей по условию - если в отображаемом контенте есть указанный шорткод.
// Подключение скрипта, если на странице есть указанный шорткод.
// Используем фильтр как событие.
add_filter( 'the_posts', 'has_my_shortcode' );
function has_my_shortcode( $posts ){
if( is_admin() || empty( $posts ) || ! is_main_query() ){
return $posts;
}
$shortcode_name = 'my_shortcode';
foreach( $posts as $post ){
if( has_shortcode( $post->post_content, $shortcode_name ) ){
add_action( 'wp_enqueue_scripts', 'add_my_scripts' );
break;
}
}
return $posts;
}
// скрипты подключать, если есть шорткод
function add_my_scripts() {
$theme_url = get_stylesheet_directory_uri();
wp_enqueue_script( 'my_script', "{$theme_url}/my_script.js" );
}
Подключение и проверка для отдельных страниц - is_singular()
// Подключение скриптов/стилей, если в контенте есть шорткод
add_action( 'wp_head', 'my_shortcode_styles' );
function my_shortcode_styles() {
global $post;
$shortcode_name = 'my_shortcode_name';
if(
! ( $post && is_singular() && has_shortcode( $post->post_content, $shortcode_name ) )
){
return;
}
?>
<style>
.foo{ color: red; }
</style>
<?php
}
Подключение скриптов/стилей, если виджет активен
Этот пример показывает, как подключить файл js скрипта, если активирован виджет «Календарь». По аналогии можно подключить скрипты для любого активного виджета.
## Подключение скрипта, если есть активный виджет
## ID базовый виджетов WP смотрите в описании http://wp-kama.ru/function/the_widget
add_action('wp_enqueue_scripts', 'add_calendar_widget_scripts');
function add_my_widget_scripts(){
if( ! is_active_widget( false, false, 'calendar' ) ) return; // выходим если виджет не активен
$theme_url = get_stylesheet_directory_uri();
wp_enqueue_script('my_widget_script', $theme_url .'/calendar_widget_script.js' );
}
Подробнее читайте описание функции is_active_widget().
Данные на каждый виджет WordPress, смотрите в описании функции the_widget()
Подключение скрипта при активном виджете в коде самого виджета
Этот код пригодится для разработчиков, которые создают виджет. Если у виджета есть свой отдельный код скрипта или стили. То разумнее подключить их только если виджет активирован.
// Класс виджета
class My_Widget extends WP_Widget {
function __construct() {
// Запускаем родительский класс
parent::__construct(
'идентификатор_виджета', // ID виджета, если не указать (оставить ''), то ID будет равен названию класса в нижнем регистре: my_widget
'Название виджета',
array('description' => 'Описание виджета'),
);
// скрипты/стили виджета, только если он активен
if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
add_action('wp_enqueue_scripts', array( $this, 'add_my_widget_scripts' ));
add_action('wp_head', array( $this, 'add_my_widget_style' ) );
}
}
// Вывод виджета
function widget( $args, $instance ){
$title = apply_filters( 'widget_title', $instance['title'] );
echo $args['before_widget'];
if( $title )
echo $args['before_title'] . $title . $args['after_title'];
echo 'Привет!';
echo $args['after_widget'];
}
// Сохранение настроек виджета (очистка)
function update( $new_instance, $old_instance ) {
}
// html форма настроек виджета в Админ-панели
function form( $instance ) {
}
// скрипт виджета
function add_my_widget_scripts() {
// фильтр чтобы можно было отключить скрипты
if( ! apply_filters( 'show_my_widget_script', true, $this->id_base ) )
return;
$theme_url = get_stylesheet_directory_uri();
wp_enqueue_script('my_widget_script', $theme_url .'/my_widget_script.js' );
}
// стили виджета
function add_my_widget_style() {
// фильтр чтобы можно было отключить стили
if( ! apply_filters( 'show_my_widget_style', true, $this->id_base ) )
return;
?>
<style type="text/css">
.my_widget a{ display:inline; }
</style>
<?php
}
}
Удаление версии скрипта или файла стилей из URL
При регистрации скрипта ему указывается версия. /wp-includes/css/dashicons.min.css?ver=4.9. Такую версию можно вырезать из ссылки на скрипт или файл стилей:
Удаление всех версия у всех скриптов:
// Удаляем версию скриптов
add_filter( 'script_loader_src', '_remove_script_version' );
// Удаляем версию стилей
add_filter( 'style_loader_src', '_remove_script_version' );
function _remove_script_version( $src ){
$parts = explode( '?', $src );
return $parts[0];
}
Удаление только версий WordPress:
## удаляет версию WP из преданного URL у скриптов и стилей
add_filter( 'script_loader_src', 'hb_remove_wp_version_from_src' );
add_filter( 'style_loader_src', 'hb_remove_wp_version_from_src' );
function hb_remove_wp_version_from_src( $src ) {
global $wp_version;
parse_str( parse_url( $src, PHP_URL_QUERY ), $query );
if ( ! empty($query['ver']) && $query['ver'] === $wp_version ) {
$src = remove_query_arg('ver', $src);
}
return $src;
}
Удаление авто-ссылок в комментариях
В комментариях текст в виде ссылки: http://example.com/foo превращается в ссылку автоматически. Чтобы убрать такое преобразование, вставьте в functions.php темы следующий хак:
remove_filter('comment_text', 'make_clickable', 9);
