Фронтэнд. 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', 'wp_usage' ); function wp_usage(){ echo 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.
Подключение скриптов/стилей, если в контенте есть шорткод
Build In PostПодключение и проверка на всех страницах
Этот код показывает, как подключать файл скрипта или стилей по условию - если в отображаемом контенте есть указанный шорткод.
// Подключение скрипта, если на странице есть указанный шорткод. // Используем фильтр как событие. 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);