Меняем чекбоксы на радио-кнопки в блоке выбора рубрик (таксономий)

Одним словом, как сделать, чтобы при написании поста можно было выбирать только одну рубрику?

Зачем это может понадобиться? Да откуда я знаю :) Наверное, чтобы было меньше косяков, на случай, если админкой будут пользоваться и другие люди.

Как это выглядит сейчас:

стандартный список таксономий в виде чекбоксов

Как это будет выглядеть в итоге:

новый блок с возможностью выбора только одной таксономии

Круто, да? :)

А теперь вот вам куча кода, который надо засунуть в functions.php, находящейся в папке с текущей темой.

Всё, что требуется, это в самом начале (в коде я написал, где именно) указать необходимые таксономии, либо оставить category — для обычных рубрик.

Если много у кого возникнут трудности с кодом, я напишу плагин. Жду ваших комментариев.

/*
 * главная функция
 */
function tr_new_taxonomy_box() {
 
	// перечислить список таксономий через запятую
	$choosed_taxonomies = array( 'game', 'category' );
 
	if ( empty($choosed_taxonomies) )
		return;
 
	foreach ( $choosed_taxonomies as $tax_name ) {
		$taxonomy = get_taxonomy( $tax_name );
 
		// метабокс будет добавляться только для таксономий с иерархией
		if ( !$taxonomy->hierarchical || !$taxonomy->show_ui || empty($taxonomy->object_type) )
			continue;
 
		foreach ( $taxonomy->object_type as $post_type ) {
 
			// удаляем стандартный метабокс
			remove_meta_box( "{$tax_name}div", $post_type, 'side' );
 
			// добавляем собственный
			add_meta_box( "unique-{$tax_name}-div", $taxonomy->labels->singular_name, 'tr_tax_metabox', $post_type, 'side', 'high', array('taxonomy' => $tax_name) );
		}
	}
}
add_action( 'admin_menu', 'tr_new_taxonomy_box' );
 
/*
 * функция для вывода непосредственно списка элементов таксономий
 */
function tr_print_radiolist( $post_id, $taxonomy ) {
	$terms = get_terms( $taxonomy, array('hide_empty' => false, 'parent'  => 0) );
	if ( empty($terms) )
		return;
 
	// значение аттрибута name для всех радио-кнопок
	$name = ( $taxonomy == 'category' ) ? 'post_category' : "tax_input[{$taxonomy}]";
 
	// определяем, к каким рубрикам относится текущий пост
	$current_post_terms = get_the_terms( $post_id, $taxonomy );
	$current = array();
	if ( !empty($current_post_terms) ) {
		foreach ( $current_post_terms as $current_post_term )
			$current[] = $current_post_term->term_id;
	}
 
	// вывод списка
	$list = '';
	foreach ( $terms as $term ) {
		$list .= "<li id='{$taxonomy}-{$term->term_id}'>";
		$list .= "<label class='selectit'>";
		$list .= "<input type='radio' name='{$name}[]' value='{$term->term_id}' ".checked( in_array($term->term_id, $current), true, false )." id='in-{$taxonomy}-{$term->term_id}' />";
		$list .= " {$term->name}</label>";
		$list .= "</li>\n";
 
		// если вам наплевать на вложенные рубрики, то цикл foreach можно закончить прямо здесь
		$childs = get_terms( $taxonomy, array('hide_empty' => false, 'parent'  => $term->term_id));
		if ( count($childs) > 0 ){
			$list .= "<ul class='children'>";
			foreach ($childs as $child){
				$list .= "<li id='{$taxonomy}-{$child->term_id}'>";
				$list .= "<label class='selectit'>";
				$list .= "<input type='radio' name='{$name}[]' value='{$child->term_id}' ".checked( in_array($child->term_id, $current), true, false )." id='in-{$taxonomy}-{$child->term_id}' />";
				$list .= " {$child->name}</label>";
				$list .= "</li>\n";
			}
			$list .= "</ul>";
		}
	}
	echo $list;
}
 
/*
 * содержимое метабокса
 */
function tr_tax_metabox( $post, $box ) {
	if ( !isset($box['args']) || !is_array($box['args']) )
		$args = array();
	else
		$args = $box['args'];
 
	$defaults = array('taxonomy' => 'category');
	extract( wp_parse_args($args, $defaults), EXTR_SKIP );
	$tax = get_taxonomy($taxonomy);
 
	$name = ( $taxonomy == 'category' ) ? 'post_category' : 'tax_input[' . $taxonomy . ']';
 
	$metabox = "<div id='taxonomy-{$taxonomy}' class='categorydiv'>";
	$metabox .= "<input type='hidden' name='{$name}' value='0' />";
	$metabox .= "<ul id='{$taxonomy}-tabs' class='category-tabs'>";
	$metabox .= "<li class='tabs'><a href='#{$taxonomy}-all' tabindex='3'>{$tax->labels->all_items}</a></li>";
	$metabox .= "</ul>";
	$metabox .= "<div id='{$name}-all' class='tabs-panel'>";
	$metabox .= "<ul id='{$taxonomy}checklist' class='list:{$taxonomy} categorychecklist form-no-clear'>";
	echo $metabox;
 
	tr_print_radiolist( $post->ID, $taxonomy );
 
	echo "</ul></div></div>";
}
Подпишитесь, чтобы раз в неделю получать свежие статьи с блога по email.

Смотрите также

Комментарии 8

  • Павел20 октября 2013 в 13:10 #

    Здравствуйте Михаил! Как сделать чтобы по умолчанию УЖЕ была выбрана любая кнопка (первая либо последняя), чтобы если автор забудет отметить категорию, то запись все-равно опубликовалась в одной из категорий?

    • Миша20 октября 2013 в 18:10 #

      Добрый день,
      например добавляем счетчик в цикле вывода рубрик и там, где переменная счетчик будет равна 1, приписываем к радио-кнопке атрибут checked="checked"

  • Павел20 октября 2013 в 20:10 #

    Дорогой Михаил, а вы не могли бы написать короткую пошаговую заметку подробнее как это можно реализовать? Заранее очень благодарен.

    Постоянный читатель вашего сайта.

    • Миша21 октября 2013 в 11:10 #

      Так, меняем вторую половину функции tr_print_radiolist. Времени протестировать у меня не было, отпишитесь, если всё работает.

      // вывод списка
      	$list = '';
      	$count = 1;
      	foreach ( $terms as $term ) {
      		if( $count == 1 && empty($current) ) { $current[] = $term->term_id; }
      		$list .= "<li id='{$taxonomy}-{$term->term_id}'>";
      		$list .= "<label class='selectit'>";
      		$list .= "<input type='radio' name='{$name}[]' value='{$term->term_id}' ".checked( in_array($term->term_id, $current), true, false )." id='in-{$taxonomy}-{$term->term_id}' />";
      		$list .= " {$term->name}</label>";
      		$list .= "</li>\n";
       
      		// если вам наплевать на вложенные рубрики, то цикл foreach можно закончить прямо здесь
      		$childs = get_terms( $taxonomy, array('hide_empty' => false, 'parent'  => $term->term_id));
      		if ( count($childs) > 0 ){
      			$list .= "<ul class='children'>";
      			foreach ($childs as $child){
      				$list .= "<li id='{$taxonomy}-{$child->term_id}'>";
      				$list .= "<label class='selectit'>";
      				$list .= "<input type='radio' name='{$name}[]' value='{$child->term_id}' ".checked( in_array($child->term_id, $current), true, false )." id='in-{$taxonomy}-{$child->term_id}' />";
      				$list .= " {$child->name}</label>";
      				$list .= "</li>\n";
      			}
      			$list .= "</ul>";
      		}
      		$count++;
      	}
      	echo $list;
  • Павел22 октября 2013 в 03:10 #

    Благодарю вас! Все прекрасно работает! А где форма пожертвований? :)

  • Лёша7 января 2014 в 14:01 #

    Подскажите, Михаил, а как то можно, начиная вот отсюда:
    "// если вам наплевать на вложенные рубрики, то цикл foreach можно закончить прямо здесь"

    Вывести лишь дочерние рубрики с определёнными ID?

    • Миша8 января 2014 в 08:01 #

      нужно добавить туда условие:

      if( $child->term_id == 55){
      	/* выводим чекбокс рубрики с ID 55 */
      }

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Для того, чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или авторизуйтесь на сайте.
Получайте новости блога по email или следите за мной в социальных сетях.
  • Миша: Добрый день! В принципе вам только немного нужно доработать код из этого поста - категории уже есть, цена - это и так...

  • eveniy: Добрый день Михаил, подскажите на примере как добавить свои произвольные поля в в вашу форму фильтрации: Я так понимаю...

  • Миша: Отлично! )

  • Дмитрий: сам разобрался: в настройках кастомного типа записи недавно оптимизировал настройки и переоптимизировал: в аргументе 'ta...

  • Дмитрий: У меня по какой-то причине пропало отображение (как в колонке меню слева, так и метабокс в записях ) раздела рубрик для...