WordPress как на ладони
wordpress jino

Фронтэнд. 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)

Создаваемым миниатюрам загружаемых изображений как правило не хватает резкости. Иногда они выглядят нормально, но это только иногда... Ну, и резкость миниатюрам еще никогда не мешала smile

Код ниже будет работать для всех создаваемых промежуточных размеров. Код рассчитан только на библиотеку 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 заголовки ответа сервера, там это видно:

  1. откройте панель-разработчика в браузере Google Chrome (ctrl+shift+i)
  2. перейдите во вкладку "Сеть"
  3. перезагрузите страницу в браузере и кликните на первую строку (это запрос HTML кода страницы)
  4. смотрите в заголовки.

Как посмотреть заголовки ответа сервера

Если сжатие еще не включено, то вставьте код ниже в 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') );
	}
}
к началу

Время генерации страницы

Выведем данные о том сколько запросов было сделано к базе данных для генерации страницы.

/**
 * Выводит данные о кол-ве запросов к БД, время выполнения скрипта и размер затраченной памяти.
 *
 * @param boolean [$visible = true] Выводить как есть или спрятать в HTML комментарий, чтобы данные
 *                                   не было видно в браузере, но их можно было посмотреть в HTML коде.
 * Функцию performance() нужно использовать в конце страницы. 
 * Чтобы автоматически добавить вывод этих данных, предлагаю воспользоваться хуками:
 */
add_filter('admin_footer_text', 'performance'); // в подвале админки
add_filter('wp_footer', 'performance'); // в подвале сайта
function performance(){
	$stat = sprintf('SQL: %d за %.3f sec. %.2f MB', get_num_queries(), timer_stop(0, 3), (memory_get_peak_usage() / 1024 / 1024) );

	echo $stat; // видно
	//echo "<!-- $stat -->"; // скрыто
}
к началу

Ссылка (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://site.ru/zapis/"><img class="alignnone size-medium wp-image-126" src="http://site.ru/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', array( & $wp_embed, 'run_shortcode' ), 8 );
add_filter( 'widget_text', array( & $wp_embed, 'autoembed'), 8 );
к началу

Подключение скриптов/стилей если в контенте есть шорткод

Этот код показывает, как подключать файл скрипта или стилей по условию - если в отображаемом контенте есть указанный шорткод.

## Подключение скрипта, если на странице есть указанный шорткод.
## используем фильтр как событие.
add_filter('the_posts', 'has_my_shortcode');
function has_my_shortcode( $posts ){
	if( is_admin() )        return $posts; // выходим, если админка
	if( empty($posts) )     return $posts; // выходим, если нет данных
	if( ! is_main_query() ) return $posts; // проверяем только для основного запроса
	//if( ! is_singular() ) return $posts; // выходим, если это не отдельная запись

	$shortcode_name = '[my_shortcode'; // шорткод искать в контенте записей

	foreach( $posts as $post ){
		if( strpos($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' );
}
к началу

Подключение скриптов/стилей если виджет активен

Этот пример показывает, как подключить файл 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
	}
}
к началу

Удаление авто-ссылок в комментариях

В комментариях текст в виде ссылки: http://site.ru/foo превращается в ссылку автоматически. Чтобы убрать такое преобразование, вставьте в functions.php темы следующий хак:

remove_filter('comment_text', 'make_clickable', 9);
Фронтэнд. 15+ хуков для functions.php 3 комментария
  • campusboy1381 cайт: wp-plus.ru
    @

    Спасибо за выкладку! Частенько некоторые подобные наработки использую, ибо маст хев! smile

    Ответить3 месяца назад #
  • приветствую, спасибо за подборку! только вот никак не могу понять почему не работает хук - "Время генерации страницы"
    вставил код 1 в 1 как ты написал, но на сайт ничего так и не вывело (ни в коомментах, ни на странице)

    • Wp 4.7, сборка bedrock + timber (тема). Если есть идеи почему не сработало и что надо подправить?
    Ответить2 месяца назад #
    • Kama4192

      $visible = true нужно было поставить. Сделал этот параметр по умолчанию - должно работать.

      Ответить2 месяца назад #

Здравствуйте, !

Ваш комментарий