# Регистрируем таксономию без привязки к типу записей
В WordPress есть одна особенность: нельзя создать таксономии независимо, без привязки к типу записей. Можно зарегистрировать таксономию, но при этом при переходе на страницу создания новых элементов (терминов) мы окажемся во вкладке "Записи" в панели администратора. Мы же хотим создать собственную страницу таксономии в панели управления. Давайте разберем это по шагам.
## Задача
Мне нужно сохранить некоторые данные (строки) с возможностью добавления новых. Эти данные (строки) будут примером навыков пользователей (например, пользователь умеет готовить, убирать, стирать).
Чтобы избежать написания большого количества кода и иметь возможность легко создавать, изменять и удалять эти навыки (число которых может превышать 2000), я решил создать пользовательскую таксономию в WordPress.
### Преимущества:
- Легкость регистрации таксономии.
- Мы получаем таблицу с пагинацией и поиском.
- Возможность добавлять, изменять и удалять данные, а также расширять их с помощью метаданных терминов.
- Доступ к целому набору функций WP для отображения и управления элементами нашей таксономии.
### Недостатки:
- Неиспользуемые поля в таблице таксономии, но это мелочь.
Итак, задача — создать таксономию, не привязанную ни к одному типу записей, и добавить ее в меню панели управления.
## Решение
Теперь создадим нашу таксономию. Она нам нужна только для хранения данных, поэтому она не будет публичной (невидима на фронтенде сайта) и не будет иметь типичных параметров таксономии.
### Создание таксономии "Навыки"
```php
add_action( 'init', function (){
register_taxonomy( 'skills', null, array(
'labels' => array(
'name' => 'Навыки',
'singular_name' => 'Навык',
'add_new_item' => 'Добавить новый навык',
),
'public' => false,
'show_ui' => true, // равно параметру public
'show_in_rest' => false, // не добавляем в REST API
'hierarchical' => false,
'update_count_callback' => '__return_null',
) );
}, 20 );
Добавление пункта меню для таксономии в админ-панели
add_action( 'admin_menu', 'add_skills_menu_item' );
function add_skills_menu_item(){
add_menu_page( 'Навыки', 'Навыки', 'manage_options', "edit-tags.php?taxonomy=skills", null, 'dashicons-awards', 9 );
}
Так мы получаем страницу таксономии в панели управления:
Но если мы перейдем на страницу таксономии "Навыки", то окажемся на вкладке "Записи".
Теперь сделаем так, чтобы активным пунктом меню была наша таксономия, а не вкладка "Записи". В WordPress нет встроенных хуков для простого решения этой задачи, поэтому воспользуемся обходным путем.
Изменяем код добавления пункта меню
/**
* Добавляем пункт меню для таксономии в админ-панели.
*/
add_action( 'admin_menu', 'add_skills_menu_item' );
function add_skills_menu_item() {
global $menu;
$tax_name = 'skills';
$menu_title = 'Навыки';
$capability = 'manage_options';
$is_skills = ( ( $_GET['taxonomy'] ?? '' ) === $tax_name );
// Удаляем 'current' для записей (по умолчанию таксономия прикрепляется к ним)
if( $is_skills ){
add_filter( 'parent_file', '__return_false' );
}
// Добавляем пункт меню
add_menu_page( $menu_title, $menu_title, $capability, "edit-tags.php?taxonomy=$tax_name", null, 'dashicons-awards', 9 );
// Настраиваем параметры добавленного пункта меню
$menu_item_key = key( wp_list_filter( $menu, [ $menu_title ] ) );
$menu_item = & $menu[ $menu_item_key ];
foreach( $menu_item as & $val ){
// Добавляем класс 'current' где необходимо
if( false !== strpos( $val, 'menu-top' ) ){
$val = 'menu-top' . ( $is_skills ? ' current' : '' );
}
$val = preg_replace( '~toplevel_page[^ ]+~', "toplevel_page_$tax_name", $val );
}
}
Результат
Готово!
Дополнительные настройки
Моя задача заключалась в том, чтобы скрыть ненужные поля и добавить поле для массового добавления навыков.
Вот полн��й код с учетом всех изменений:
'Навыки',
'singular_name' => 'Навык',
'add_new_item' => 'Добавить новый навык',
];
public static function init() {
add_action( 'init', static function() {
self::register_taxonomy();
self::bulk_add_terms_handler();
} );
// Добавляем пункт меню для таксономии в админ-панели
add_action( 'admin_menu', [ __CLASS__, 'add_tax_menu_item' ] );
// Форма для массового добавления навыков
add_action( self::$tax_name . '_add_form', [ __CLASS__, 'bulk_add_terms_form' ] );
// Кастомные стили на странице таксономии и на странице редактирования элемента.
add_action( 'admin_head', [ __CLASS__, 'styles_on_edit_term_page' ] );
// Убираем ненужные колонки
$edit_page_key = 'edit-' . self::$tax_name;
add_filter( "manage_{$edit_page_key}_columns", [ __CLASS__, 'remove_unused_columns' ] );
}
private static function register_taxonomy(): void {
register_taxonomy(
self::$tax_name,
null,
[
'labels' => self::$menu_labels,
'public' => false,
'show_ui' => true, // равно параметру public
'show_in_rest' => false, // не добавляем в REST API
'hierarchical' => false,
'update_count_callback' => '__return_null',
]
);
}
public static function add_tax_menu_item(): void {
global $menu;
$tax_name = self::$tax_name;
$is_the_tax = ( ( $_GET['taxonomy'] ?? '' ) === self::$tax_name );
// Удаляем 'current' для записей (по умолчанию таксономия привязана там)
if( $is_the_tax ){
add_filter( 'parent_file', '__return_false' );
}
// Добавляем пункт меню
add_menu_page(
self::$menu_title,
self::$menu_title,
self::$capability,
'edit-tags.php?taxonomy=' . self::$tax_name,
null,
'dashicons-awards',
9
);
// Настраиваем параметры добавленного пункта меню
$menu_item_key = key( wp_list_filter( $menu, [ self::$menu_title ] ) );
$menu_item = & $menu[ $menu_item_key ];
foreach( $menu_item as & $val ){
// Добавляем класс 'current' где необходимо
if( false !== strpos( $val, 'menu-top' ) ){
$val = 'menu-top' . ( $is_the_tax ? ' current' : '' );
}
$val = preg_replace( '~toplevel_page[^ ]+~', "toplevel_page_$tax_name", $val );
}
}
/**
* Обрабатываем запрос на массовое добавление навыков.
*/
public static function bulk_add_terms_handler(): void {
$new_terms = trim( $_POST[ self::$request_key ] ?? '' );
if( ! $new_terms || ! current_user_can( self::$capability ) ){
return;
}
$new_terms = wp_unslash( $new_terms );
$new_terms = array_filter( array_map( 'trim', explode( "n", $new_terms ) ) );
$err_names = [];
foreach( $new_terms as $new_term_name ){
$data = wp_insert_term( $new_term_name, self::$tax_name );
if( is_wp_error( $data ) ){
$err_names[ $new_term_name ] = $data->get_error_message();
}
}
// Сообщение о результате обработки запроса
add_action( 'admin_notices', function() use ( $err_names, $new_terms ) {
$added_count = count( $new_terms ) - count( $err_names );
$message = "Добавлено терминов: $added_count
";
if( $err_names ){
$message .= '';
$message .= 'Не удалось добавить:
';
foreach( $err_names as $skill_name => $err_msg ){
$message .= '' . esc_html( $skill_name ) . ": $err_msg
";
}
$message .= "
";
}
echo '' . $message . '';
} );
}
public static function bulk_add_terms_form(): void {
if( ! current_user_can( self::$capability ) ){
return;
}
// Код выводится внутри существующей формы, поэтому мы закроем ее и откроем свою
?>
Теперь у вас есть таксономия "Навыки", с которой можно легко работать, добавлять и редактировать элементы.