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

Админка. 15+ хуков для functions.php

Очередная подборка хаков, которые можно использовать для админ-панели WordPress. Все коды проверены на работоспособность до версии WP 4.7. Здесь собраны популярные хуки и отсортированы они в порядке популярности (на основе сайта wordpress.stackexchange.com).

Оглавление:

Все настройки сайта на одной странице

Включение спрятанной страница админ панели. Этот маленький кусок кода, добавит еще один пункт в меню настроек сайта. Перейдя на добавленную страницу, вы увидите все настройки сайта сразу. На такую страницу можно попасть по ссылке: example.com/wp-admin/options.php.

Код срабатывает только для администратора сайта, другие роли новый пункт меню не увидят.

## Добавляет ссылку на страницу всех настроек в пункт меню админки "Настройки"
add_action('admin_menu', 'all_settings_link');
function all_settings_link(){
	add_options_page( __('All Settings'), __('All Settings'), 'manage_options', 'options.php?foo' );
}

Удаляем уведомление об обновлении WordPress для всех кроме админа

add_action( 'admin_head', function () {
	if ( ! current_user_can( 'manage_options' ) ) {
		remove_action( 'admin_notices', 'update_nag', 3 );
		remove_action( 'admin_notices', 'maintenance_nag', 10 );
	}
} );

Старый вариант, в комментах сказали больше не работает:

## удаляет сообщение о новой версии WordPress у всех пользователей кроме администратора
if( is_admin() && ! current_user_can('manage_options') ){
	add_action( 'init', function(){
		remove_action( 'init', 'wp_version_check' );
	}, 2 );
	add_filter( 'pre_option_update_core', '__return_null');
}

Удаление метабоксов на странице редактирования записи

На странице редактирования записи очень часто находятся никогда не используемые метабоксы. И чтобы немного ускорить админку и убрать лишнее из интерфейса, их можно удалить. Подробнее читайте в описании функции remove_meta_box()

## Удаление метабоксов на странице редактирования записи
add_action('admin_menu','remove_default_post_screen_metaboxes');
function remove_default_post_screen_metaboxes() {
	// для постов
	remove_meta_box( 'postcustom','post','normal' ); // произвольные поля
	remove_meta_box( 'postexcerpt','post','normal' ); // цитата
	remove_meta_box( 'commentstatusdiv','post','normal' ); // комменты
	remove_meta_box( 'trackbacksdiv','post','normal' ); // блок уведомлений
	remove_meta_box( 'slugdiv','post','normal' ); // блок альтернативного названия статьи
	remove_meta_box( 'authordiv','post','normal' ); // автор

	// для страниц
	remove_meta_box( 'postcustom','page','normal' ); // произвольные поля
	remove_meta_box( 'postexcerpt','page','normal' ); // цитата
	remove_meta_box( 'commentstatusdiv','page','normal' ); // комменты
	remove_meta_box( 'trackbacksdiv','page','normal' ); // блок уведомлений
	remove_meta_box( 'slugdiv','page','normal' ); // блок альтернативного названия статьи
	remove_meta_box( 'authordiv','page','normal' ); // автор
}

В WordPress есть особенность, которая позволяет изменить порядок пунктов главного меню в админке как угодно. Об этой возможности знают далеко не все. По умолчанию она не работает - её нужно включить через хук custom_menu_order. Подробнее смотрите в коде ниже.

Код ниже изменит порядок меню. Сначала будет идти «Страницы», потом «Записи», а потом произвольный тип записей «events». Меняя порядок элементов массива, можно изменить порядок пунктов меню как угодно.

## Произвольный порядок пунктов в главном меню админки
if( is_admin() ){
	add_filter('custom_menu_order', '__return_true'); // включаем ручную сортировку
	add_filter('menu_order', 'custom_menu_order'); // ручная сортировка
	function custom_menu_order( $menu_order ){
		/*
		$menu_order - массив где элементы меню выставлены в нужном порядке.
		Array(
			[0] => index.php
			[1] => separator1
			[2] => edit.php
			[3] => upload.php
			[4] => edit.php?post_type=page
			[5] => edit-comments.php
			[6] => edit.php?post_type=events
			[7] => separator2
			[8] => themes.php
			[9] => plugins.php
			[10] => snippets
			[11] => users.php
			[12] => tools.php
			[13] => options-general.php
			[14] => separator-last
			[15] => edit.php?post_type=cfs
		)
		*/
		if( ! $menu_order ) return true;

		return array(
			'index.php', // консоль
			'edit.php?post_type=page', // страницы
			'edit.php', // посты
			'edit.php?post_type=events', // записи типа events
		);
	}
}

Перемещаем выбранную рубрику сверху на свое место в иерархии

  1. Есть древовидная структура категорий.
  2. Я публикую запись и помещаю её в дочернюю рубрику.
  3. В результате, выбранная рубрика находится вверху, а нужно, чтобы она была на своем месте, в иерархии рубрик.

##  отменим показ выбранного термина наверху в checkbox списке терминов
add_filter( 'wp_terms_checklist_args', 'set_checked_ontop_default', 10 );
function set_checked_ontop_default( $args ) {
	// изменим параметр по умолчанию на false
	if( ! isset($args['checked_ontop']) )
		$args['checked_ontop'] = false;

	return $args;
}

Источник

Удаление вкладок «Все рубрики» и «Часто используемые» у метабокса рубрик в админке

Этот хак я часто использую то тут то там. По-моему это удобно!

Код удалить такие вкладки и у метабоксов произвольных древовидных таксономий.

# Убираем вкладку "Часто используемое" для метабокса рубрик для всех записей
add_action( 'admin_head', 'func_hook_admin_styles' );

function func_hook_admin_styles() {

	$cs = get_current_screen();

	// не страница редактирования записи
	if ( $cs->base !== 'post' || empty( $cs->post_type ) ) {
		return;
	}
	?>
	<style>
		.postbox div.tabs-panel{ max-height:1200px; border:0; }

		.category-tabs{ display:none; }
	</style>
	<?php
}

Изменим checkbox на radio в виджете рубрик

Если на сайте предполагается указывать всегда только одну рубрику для записи, то для удобства можно поменять чекбоксы в виджете категорий на радио кнопки. Так при изменении рубрики, ранее выбранная рубрика автоматически будет отменяться и для записи всегда будет указана только одна рубрика.

Пример ниже показывает как сделать такое для таксономий category и my_category.

Вариант 1:

## Переделаем checkbox в radio на страницах записей
add_action( 'admin_print_footer_scripts', 'func_hook_admin_footer_scripts', 99 );
function func_hook_admin_footer_scripts(){
	if( get_current_screen()->base !== 'post' )
		return;
	?>
	<script>
		[ 'category', 'my_category' ].forEach(function(taxname){
			jQuery( '#' + taxname + 'div input[type="checkbox"]' ).prop( 'type', 'radio' );
		})
	</script>
	<?php
}

Вариант 2 (для перфекционистов - добавляет скрипт только когда есть виджет таксономии)

## Переделаем checkbox в radio на страницах записей
add_action( 'admin_print_footer_scripts', 'func_hook_admin_footer_scripts', 99 );
function func_hook_admin_footer_scripts(){

	// для каких таксономий нужно менять checkbox на radio
	$taxonomies = [ 'category', 'my_category' ];
	$cs = get_current_screen();
	if( $cs->base === 'post' && ($taxonomies = array_intersect( get_object_taxonomies( $cs->post_type ), $taxonomies )) ){
		?>
		<script>
			<?= json_encode($taxonomies) ?>.forEach(function(taxname){
				jQuery( '#' + taxname + 'div input[type="checkbox"]' ).prop( 'type', 'radio' );
			})
		</script>
		<?php
	}

}

Добавляем типы записей, таксономии в виджет «На виду» («Прямо сейчас») в консоли

Чтобы в консоли сразу было видны числа - сколько записей каждого типа создано, можно расширить виджет «На виду» (раньше он назывался «Прямо сейчас»).

Виджет На виду
## Добавляем все типы записей в виджет "Прямо сейчас" в консоли
add_action( 'dashboard_glance_items' , 'add_right_now_info' );
function add_right_now_info( $items ){

	if( ! current_user_can('edit_posts') ) return $items; // выходим

	// типы записей
	$args = array( 'public' => true, '_builtin' => false );

	$post_types = get_post_types( $args, 'object', 'and' );

	foreach( $post_types as $post_type ){
		$num_posts = wp_count_posts( $post_type->name );
		$num       = number_format_i18n( $num_posts->publish );
		$text      = _n( $post_type->labels->singular_name, $post_type->labels->name, intval( $num_posts->publish ) );

		$items[] = "<a href=\"edit.php?post_type=$post_type->name\">$num $text</a>";
	}

	// таксономии
	$taxonomies = get_taxonomies( $args, 'object', 'and' );

	foreach( $taxonomies as $taxonomy ){
		$num_terms = wp_count_terms( $taxonomy->name );
		$num       = number_format_i18n( $num_terms );
		$text      = _n( $taxonomy->labels->singular_name, $taxonomy->labels->name , intval( $num_terms ) );

		$items[] = "<a href='edit-tags.php?taxonomy=$taxonomy->name'>$num $text</a>";
	}

	// пользователи
	global $wpdb;

	$num  = $wpdb->get_var("SELECT COUNT(ID) FROM $wpdb->users");
	$text = _n( 'User', 'Users', $num );

	$items[] = "<a href='users.php'>$num $text</a>";

	return $items;
}

Подробнее про код читайте в отдельной статье.

Добавляет миниатюры записи в таблицу записей в админке

В таблице записей в админке иногда очень удобно видеть какая для записи установлена миниатюра или первая загруженная картинка. Такую колонку легко можно добавить, установив небольшой код.

Колонка в списке записей с миниатюрами записей

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

## Добавляет миниатюры записи в таблицу записей в админке
if(1){
	add_action('init', 'add_post_thumbs_in_post_list_table', 20 );
	function add_post_thumbs_in_post_list_table(){
		// проверим какие записи поддерживают миниатюры
		$supports = get_theme_support('post-thumbnails');

		// $ptype_names = array('post','page'); // указывает типы для которых нужна колонка отдельно

		// Определяем типы записей автоматически
		if( ! isset($ptype_names) ){
			if( $supports === true ){
				$ptype_names = get_post_types(array( 'public'=>true ), 'names');
				$ptype_names = array_diff( $ptype_names, array('attachment') );
			}
			// для отдельных типов записей
			elseif( is_array($supports) ){
				$ptype_names = $supports[0];
			}
		}

		// добавляем фильтры для всех найденных типов записей
		foreach( $ptype_names as $ptype ){
			add_filter( "manage_{$ptype}_posts_columns", 'add_thumb_column' );
			add_action( "manage_{$ptype}_posts_custom_column", 'add_thumb_value', 10, 2 );
		}
	}

	// добавим колонку
	function add_thumb_column( $columns ){
		// подправим ширину колонки через css
		add_action('admin_notices', function(){
			echo '
			<style>
				.column-thumbnail{ width:80px; text-align:center; }
			</style>';
		});

		$num = 1; // после какой по счету колонки вставлять новые

		$new_columns = array( 'thumbnail' => __('Thumbnail') );

		return array_slice( $columns, 0, $num ) + $new_columns + array_slice( $columns, $num );
	}

	// заполним колонку
	function add_thumb_value( $colname, $post_id ){
		if( 'thumbnail' == $colname ){
			$width  = $height = 45;

			// миниатюра
			if( $thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true ) ){
				$thumb = wp_get_attachment_image( $thumbnail_id, array($width, $height), true );
			}
			// из галереи...
			elseif( $attachments = get_children( array(
				'post_parent'    => $post_id,
				'post_mime_type' => 'image',
				'post_type'      => 'attachment',
				'numberposts'    => 1,
				'order'          => 'DESC',
			) ) ){
				$attach = array_shift( $attachments );
				$thumb = wp_get_attachment_image( $attach->ID, array($width, $height), true );
			}

			echo empty($thumb) ? ' ' : $thumb;
		}
	}
}

Отключаем пинги на свои записи

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

Чтобы отключить такое странное поведение, вставьте следующий код в functions.php:

# Отключаем пинги на свои же посты
add_action( 'pre_ping', 'kama_disable_inner_ping' );
function kama_disable_inner_ping( & $links ){

	foreach( $links as $k => $val ){
		if( false !== strpos( $val, str_replace('www.', '', $_SERVER['HTTP_HOST']) ) )
			unset( $links[$k] );
	}
}

Подробнее читайте в записи: Отключаем пинги на свои записи

Отключаем все стандартные виджеты WordPress

Чтобы отключить все виджеты WordPress, которые существуют по умолчанию, вставьте в functions.php такой код:

add_action( 'widgets_init', 'unregister_basic_widgets' );

function unregister_basic_widgets(){

	unregister_widget( 'WP_Widget_Pages' );            // Виджет страниц
	unregister_widget( 'WP_Widget_Calendar' );         // Календарь
	unregister_widget( 'WP_Widget_Archives' );         // Архивы
	unregister_widget( 'WP_Widget_Links' );            // Ссылки
	unregister_widget( 'WP_Widget_Meta' );             // Мета виджет
	unregister_widget( 'WP_Widget_Search' );           // Поиск
	unregister_widget( 'WP_Widget_Text' );             // Текст
	unregister_widget( 'WP_Widget_Categories' );       // Категории
	unregister_widget( 'WP_Widget_Recent_Posts' );     // Последние записи
	unregister_widget( 'WP_Widget_Recent_Comments' );  // Последние комментарии
	unregister_widget( 'WP_Widget_RSS' );              // RSS
	unregister_widget( 'WP_Widget_Tag_Cloud' );        // Облако меток
	unregister_widget( 'WP_Nav_Menu_Widget' );         // Меню
}

Изменение названия типа записи

По умолчанию в WordPress есть два типа записи: Записи (post) и Страницы (page). Этот пример показывает как изменить их названия по всей админке.

Иногда удобно или логично заменить слово «Записи» и все связанные названия «Записей» в админке на другое слово, например «Посты». Такую замену я сделал на этом сайте:

Замена названия типа записи на другое

Код простой и работает очень быстро:

add_filter( 'post_type_labels_post', 'rename_posts_labels' );

# заменим слово "записи" на "посты" для типа записей 'post'
function rename_posts_labels( $labels ){
	// заменять автоматически нельзя: Запись = Статья, а в тексте получим "Просмотреть статья"

	$new = [
		'name'                  => 'Посты',
		'singular_name'         => 'Пост',
		'add_new'               => 'Добавить пост',
		'add_new_item'          => 'Добавить пост',
		'edit_item'             => 'Редактировать пост',
		'new_item'              => 'Новый пост',
		'view_item'             => 'Просмотреть пост',
		'search_items'          => 'Поиск постов',
		'not_found'             => 'Посты не найдены.',
		'not_found_in_trash'    => 'Посты в корзине не найдены.',
		'parent_item_colon'     => '',
		'all_items'             => 'Все посты',
		'archives'              => 'Архивы постов',
		'insert_into_item'      => 'Вставить в пост',
		'uploaded_to_this_item' => 'Загруженные для этого поста',
		'featured_image'        => 'Миниатюра поста',
		'filter_items_list'     => 'Фильтровать список постов',
		'items_list_navigation' => 'Навигация по списку постов',
		'items_list'            => 'Список постов',
		'menu_name'             => 'Посты',
		'name_admin_bar'        => 'Пост', // пункте "добавить"
	];

	return (object) array_merge( (array) $labels, $new );
}

Подробнее о том как появился этот код читайте в вопросе.

Отключим уведомление об обновлении для неактивных плагинов

add_filter( 'transient_update_plugins', 'update_active_plugins' );    // Hook for 2.8.+
//add_filter( 'option_update_plugins', 'update_active_plugins' );    // Hook for 2.7.x
function update_active_plugins( $value = '' ){
	/*
	The $value array passed in contains the list of plugins with time
	marks when the last time the groups was checked for version match
	The $value->reponse node contains an array of the items that are
	out of date. This response node is use by the 'Plugins' menu
	for example to indicate there are updates. Also on the actual
	plugins listing to provide the yellow box below a given plugin
	to indicate action is needed by the user.
	*/
	if( (isset($value->response)) && (count($value->response)) ){

		// Get the list cut current active plugins
		$active_plugins = get_option('active_plugins');
		if ($active_plugins) {

			//  Here we start to compare the $value->response
			//  items checking each against the active plugins list.
			foreach($value->response as $plugin_idx => $plugin_item) {

				// If the response item is not an active plugin then remove it.
				// This will prevent WordPress from indicating the plugin needs update actions.
				if (!in_array($plugin_idx, $active_plugins))
					unset($value->response[$plugin_idx]);
			}
		}
		else {
			 // If no active plugins then ignore the inactive out of date ones.
			foreach($value->response as $plugin_idx => $plugin_item) {
				unset($value->response);
			}
		}
	}
	return $value;
}

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

Авто-удаление license.txt и readme.html

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

Этот код будет отличным дополнением к плагину Clearfy.

Как работает? Проверяет наличие файла, когда вы заходите в админку. Если файл есть, то PHP пытается его удалить автоматически. Если для удаления недостаточно прав, то админ увидит сообщение о том, что нужно удалить файлы license.txt и readme.html.

## Удаление файлов license.txt и readme.html для защиты
## ver 2
if( is_admin() && ! defined('DOING_AJAX') ){
	add_action( 'init', 'remove_license_txt_readme_html' );
	function remove_license_txt_readme_html(){

		$license_file = ABSPATH .'/license.txt';
		$readme_file  = ABSPATH .'/readme.html';

		if( file_exists($license_file) && current_user_can('manage_options') ){

			$deleted = unlink($license_file) && unlink($readme_file);

			if( ! $deleted  )
				$GLOBALS['readmedel'] = 'Не удалось удалить файлы: license.txt и readme.html из папки `'. ABSPATH .'`. Удалите их вручную!';
			else
				$GLOBALS['readmedel'] = 'Файлы: license.txt и readme.html удалены из из папки `'. ABSPATH .'`.';

			add_action( 'admin_notices', function(){
				echo '<div class="error is-dismissible"><p>'. $GLOBALS['readmedel'] .'</p></div>';
			} );
		}
	}
}

Поиск-фильтр элементов таксономии по названиям в метабоксе админки

Допустим у вас на сайте очень много рубрик, например 200. Или это могут быть не стандартные рубрики а разделы для WooComerce. Находить нужную рубрику (элемент таксономии) в таком списке крайне неудобно.

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

Вставьте следующий код в functions.php темы и вы получите такой фильтр терминов:

## Фильтр элементо втаксономии для метабокса таксономий в админке.
## Позволяет удобно фильтровать (искать) элементы таксономии по назанию, когда их очень много
add_action( 'admin_print_scripts', 'my_admin_term_filter', 99 );
function my_admin_term_filter() {
	$screen = get_current_screen();

	if( 'post' !== $screen->base ) return; // только для страницы редактирвоания любой записи
	?>
	<script>
	jQuery(document).ready(function($){
		var $categoryDivs = $('.categorydiv');

		$categoryDivs.prepend('<input type="search" class="fc-search-field" placeholder="фильтр..." style="width:100%" />');

		$categoryDivs.on('keyup search', '.fc-search-field', function (event) {

			var searchTerm = event.target.value,
				$listItems = $(this).parent().find('.categorychecklist li');

			if( $.trim(searchTerm) ){
				$listItems.hide().filter(function () {
					return $(this).text().toLowerCase().indexOf(searchTerm.toLowerCase()) !== -1;
				}).show();
			}
			else {
				$listItems.show();
			}
		});
	});
	</script>
	<?php
}

Этот код показывает всю ветку если категории в иерархическом виде:

Источник. Взято из плагина Post Category Filter

Подсказки в меню админ-панели (счетчики в меню)

Если есть обновления плагинов, то в меню мы видим кружок с числом плагинов. Такие же кружки с номерами можно добавить к любому пункту меню. Например, нам нужно показывать такое уведомление, если есть записи на проверке:

add_action( 'admin_menu', 'add_user_menu_bubble' );
function add_user_menu_bubble(){
	global $menu;

	// записи
	$count = wp_count_posts()->pending; // на утверждении
	if( $count ){
		foreach( $menu as $key => $value ){
			if( $menu[$key][2] == 'edit.php' ){
				$menu[$key][0] .= ' <span class="awaiting-mod"><span class="pending-count">' . $count . '</span></span>';
				break;
			}
		}
	}
}

уведомление для меню в админке

Перекрашиваем Админ бар (тулбар) для разных окружений

Используйте wp_get_environment_type(), чтобы получить текущую среду разработки.

  • стандартный черный для Локальной среды разработки
  • cиний для QA (тестовой) и для development
  • оранжевый для staging
  • красный для production.

GitHub

<?php
/**
 * Adminpanel environment color for WordPress.
 * It helps to highlight environments in color. Developers, Content Managers,
 * and others will never confuse the environment where they work.
 *
 * Author: Andrei Pisarevskii
 * Author Email: renakdup@gmail.com
 * Author Site: https://wp-yoda.com/en/
 *
 * Version: 0.3
 * Source Code: https://gist.github.com/renakdup/36f4a8474d0cb13ecadf0393811d5330
 *
 * Licence: MIT License
 */

namespace Renakdup\AdminpanelEnvColor;

AdminpanelEnvColor::init();

final class AdminpanelEnvColor {

	public static function init() {
		add_action( 'admin_head', [ __CLASS__, 'add_admin_bar_style' ] );
		add_action( 'wp_head', [ __CLASS__, 'add_admin_bar_style' ] );
		add_action( 'admin_bar_menu', [ __CLASS__, 'add_admin_bar_env_item' ], 100 );
	}

	public static function add_admin_bar_style() {
		$adminpanel_colors = apply_filters(
			'renakdup/adminpanel_env_color/colors',
			[
				'local'       => null, // default wp color
				'development' => '#2271b1', // blue
				'staging'     => '#cc6f00', // orange
				'production'  => '#6d0d0f', // red
			]
		);

		// phpcs:disable WordPress.CodeAnalysis.AssignmentInCondition.Found, Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure, WordPress.Security.EscapeOutput.OutputNotEscaped
		if ( $color = $adminpanel_colors[ wp_get_environment_type() ] ) {
			echo '<style>
				#wpadminbar { background-color: ' . $color . '!important; }
				#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu { background-color: ' . $color . '!important; }
			</style>';
		}
		// phpcs:enable

		echo '<style>.rd_adminpanel_env_color a {
			box-shadow: inset 0 32px 5px rgba(0, 0, 0, 0.5) !important;
			padding-left: 30px !important;
			padding-right: 30px !important;
			}
		</style>';
	}

	/**
	 * @param $wp_admin_bar \WP_Admin_Bar
	 *
	 * @return void
	 */
	public static function add_admin_bar_env_item( $wp_admin_bar ) {
		$args = [
			'id'     => 'rd_adminpanel_env_color',
			'parent' => 'top-secondary',
			'title'  => 'ENV: ' . ucfirst( wp_get_environment_type() ),
			'href'   => '#',
			'meta'   => [
				'class' => 'rd_adminpanel_env_color',
				'title' => 'Your environment',
			],
		];
		$wp_admin_bar->add_node( $args );
	}
}

Чтобы изменить цвета или названия окружений, используйте фильтр renakdup/adminpanel_env_color/colors.

Чтобы отключить перекрашивание для определенных ролей, используйте remove_filter().

--

Подробнее читайте в оригинальной статье.

-

Источник: wordpress.stackexchange.com, личный опыт, вопросы этого сайта и т.д.

9 комментариев
    Войти