Реєстрація таксономії без прив’язки до типу запису

Як з’ясувалося, WordPress не дозволяє швидко і просто створити таксономію так, щоб не прив’язати її до якогось типу запису. Точніше зареєструвати таксономію без прив’язки можна, тільки при переході на сторінку створення елементів цієї таксономії ми неминуче перебуватимемо в пункті меню «Записи». А нам потрібно створити окремий пункт меню для цієї таксономії. Поясню по порядку…

Завдання

Потрібно зберігати дані (рядки), з можливістю додавати до них ще якісь дані (заздалегідь невідомо, код розширюватиметься). Далі ці дані (рядки) будуть використовуватися для користувачів WordPress (у користувачів буде налаштування скіли, наприклад, користувач вміє, готувати, прати, прибирати).

Щоб не писати купу коду, для можливості створювати, змінювати і видаляти ці скіли, кількість яких очікується в розмірі 2000 жарт, було прийнято стратегічне рішення використовувати для цих цілей таксономію WordPress .

Плюси: регнути таксономію дуже просто і відразу ми отримуємо таблицю з пагінацією та пошуком, можливість додавати, змінювати, видаляти дані, а також можливість розширювати дані за рахунок метаполів. Більш того, отримуємо цілий пакет функцій WP для виведення елементів таксономії. А якщо, наприклад, зберігати ці дані в окрему таблицю або опції, то для управління всім цим потрібно було б писати окремий код, для всього: починаючи зі створення сторінки в адмінці і закінчуючи функціями виведення елементів. А тут готово все й одразу.

Мінуси: зайві поля, що не використовуються, в таблиці таксономій, а ми на сірниках не економимо, тому мінусів немає!

Отже, завдання: створити таксономію не прив’язану до типу запису і має окремий пункт меню в адмін панелі.

Рішення

Реєструємо таксономію. Вона нам потрібна тільки для зберігання даних, тому вона буде не публічною (не видно на фронті) і без звичних параметрів таксономії:

// Створимо таксономію skills
add_action( 'init', function (){
	register_taxonomy( 'skills', null, array(
		//'label' => 'Скили', // визначається параметром $labels->name
		'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 );
}

Отримуємо:

Тепер завдання відключити підрозділ Запису та зробити активним пункт меню нашої такси. Тут у ВП все погано – підходящих хуків немає, тому хакатимемо.

Це код для якого писалася поточна нотатка:

## додамо пункт меню таксономії до адмін меню
add_action( 'admin_menu', 'add_skills_menu_item');
function add_skills_menu_item(){
	$taxname = 'skills';

	$is_skills = isset($_GET['taxonomy']) && $_GET['taxonomy'] === $taxname;

	// скасуємо 'current' для записів (за умовчанням такса туди прив'язується, навіть якщо під час реєстрації такси не вказати тип записи)
	if( $is_skills ) add_filter( 'parent_file', '__return_false' );

	// додамо пункт меню
	$menu_title = 'Скіли';
	add_menu_page( 'Скіли', $menu_title, 'manage_options', "edit-tags.php?taxonomy=$taxname", null, 'dashicons-awards', 9 );

	// Виправимо деякі параметри доданого пункту меню
	$menu_item = & $GLOBALS['menu'][ key(wp_list_filter( $GLOBALS['menu'], [$menu_title] )) ];
	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_$taxname", $val);
	}

}

Отримуємо:

Ось, власне, і все!

У моєму завданні потрібно було ще приховати непотрібні поля та додати поле для масового додавання скілів.

Весь попередній код повністю, включаючи код для дод. завдань:

<?php

// Створимо таксономію skills
add_action( 'init', function (){
	register_taxonomy( 'skills', null, array(
		//'label' => 'Скили', // визначається параметром $labels->name
		'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',
	)));

	massadd_skills_handler();
}, 20);

## додамо пункт меню таксономії до адмін меню
add_action( 'admin_menu', 'add_skills_menu_item');
function add_skills_menu_item(){
	$taxname = 'skills';

	$is_skills = isset($_GET['taxonomy']) && $_GET['taxonomy'] === $taxname;

	// скасуємо 'current' для записів (за умовчанням такса туди прив'язується, навіть якщо під час реєстрації такси не вказати тип записи)
	if( $is_skills ) add_filter( 'parent_file', '__return_false' );

	// додамо пункт меню
	$menu_title = 'Скіли';
	add_menu_page( 'Скіли', $menu_title, 'manage_options', "edit-tags.php?taxonomy=$taxname", null, 'dashicons-awards', 9 );

	// Виправимо деякі параметри доданого пункту меню
	$menu_item = & $GLOBALS['menu'][ key(wp_list_filter( $GLOBALS['menu'], [$menu_title] )) ];
	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_$taxname", $val);
	}

}

## обробка запиту на масове додавання скілів
function massadd_skills_handler(){
	if( empty($_POST['massadd_skills']) || ! trim($_POST['massadd_skills']) || ! current_user_can('manage_options') )
		return; // тільки адмін

	$new_skills = wp_unslash( trim($_POST['massadd_skills']) );
	$new_skills = array_filter( array_map( 'trim', explode( "n", $new_skills ) )));

	$err_names = [];
	foreach( $new_skills as $skill_name ){
		$data = wp_insert_term( $skill_name, 'skills' );
		if( is_wp_error($data) )
			$err_names[ $skill_name ] = $data->get_error_message();
	}

	// Повідомлення про результат запиту
	add_action( 'admin_notices', function() use ($err_names, $new_skills){
		$added_count = count($new_skills) - count($err_names);
		$message = "<p>Додано термінів: $added_count</p>";

		if($err_names) {
			$message .= '<p style="color:red;">';
			$message .= 'Неможливо додати: <br>';
			foreach( $err_names as $skill_name => $err_msg )
				$message .= '<b>'. esc_html($skill_name) . "</b>: $err_msg <br>";
			$message .= "</p>";
		}

		echo '<div class="notice notice-success is-dismissible"><div>'. $message .'</div></div>';
	} );

}

## форма масового додавання скілів
add_action('skills'.'_add_form', 'massadd_skills_form');
function massadd_skills_form(){
	if( ! current_user_can('manage_options') ) return; // тільки адмін

	// код виводиться всередині існуючої форми, тому закриємо її та відкриємо свою
	?>
	</form>

	<form method="POST" action="">
		<div class="form-field massadd-skills-wrap">
			<h2>Масове додавання скілів</h2>
			<p>Список скилів кожен на новому рядку.</p>
			<textarea name="massadd_skills" rows="5" style="width:95%"></textarea>
		</div>
	<?php
	submit_button( 'Додати скіли масово');
}

## свої стилі на сторінці таксономії skills та на сторінці редагування елемента skills
сховаємо непотрібні поля
add_action( 'admin_head', 'hide_unwanted_skill_field');
function hide_unwanted_skill_field(){
	if( get_current_screen()->id === 'edit-skills' ){
		echo '
		<style>
			.form-field.term-slug-wrap{ display:none; }
			.form-field.term-description-wrap{ display:none; }
		</style>';
	}
}

## Видалимо непотрібні колонки
add_filter( 'manage_'.'edit-skills'.'_columns', function( $columns ){
	unset( $columns['description'], $columns['posts'] );
	return $columns;
});

Отримуємо:

Залишити коментар

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *