WordPress как на ладони
Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

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

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

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

С версии 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.

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

Подключение и проверка на всех страницах

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

// Подключение скрипта, если на странице есть указанный шорткод.
// Используем фильтр как событие.
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);
2 комментария
    Войти