Как вывести только дочерние элементы таксономии без их родительских элементов?
Я создаю меню выбора возраста в админке, заполняемое из таксономии age
. Таксономия имеет иерархическую структуру:
- 18-25 (родительский, ID 183)
- 18 (дочерний)
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26-30 (родительский, ID 184)
- 26
- 27
- 28
- 29
- 30
Мне нужно вывести только дочерние элементы (18, 19 и т.д.), без родительских (18-25, 26-30). Сейчас я использую get_terms
с аргументом parent
, но он не принимает больше одного ID родителя. Вот мой текущий код, который показывает дочерние элементы для 18-25:
$ages = get_terms( 'age', array(
'hide_empty' => 0,
'parent' => '183',
));
Вот что я хочу сделать, но это не поддерживается. Я также пробовал передавать массив, но это тоже не сработало.
$ages = get_terms( 'age', array(
'hide_empty' => 0,
'parent' => '183,184',
));
Я видел функцию get_term_children, но не уверен, как её использовать, так как она тоже принимает только одно значение. Например: В этом примере создается ненумерованный список, но я могу адаптировать его для select-меню.
<?php
$termID = 183;
$taxonomyName = "age";
$termchildren = get_term_children( $termID, $taxonomyName );
echo '<ul>';
foreach ($termchildren as $child) {
$term = get_term_by( 'id', $child, $taxonomyName );
echo '<li><a href="' . get_term_link( $term->name, $taxonomyName ) . '">' . $term->name . '</a></li>';
}
echo '</ul>';
?>

Это должно сработать для вас:
$taxonomyName = "age";
//Получаем только термины верхнего уровня, устанавливая parent в 0.
$parent_terms = get_terms(
$taxonomyName,
array(
'parent' => 0,
'orderby' => 'slug',
'hide_empty' => false
)
);
echo '<ul>';
foreach ( $parent_terms as $pterm ) {
//Получаем дочерние термины
$terms = get_terms(
$taxonomyName,
array(
'parent' => $pterm->term_id,
'orderby' => 'slug',
'hide_empty' => false
)
);
foreach ( $terms as $term ) {
echo '<li><a href="'. get_term_link($term) . '">'. $term->name .'</a></li>';
}
}
echo '</ul>';

Спасибо @Manny, сработало отлично. Я взял то, что вы предоставили, и объединил это с нужным мне выпадающим меню. Отличная работа.

Смотрите ответ karimhossenbux ниже для более эффективного решения.

Вы также можете сделать так:
$terms = get_terms($taxonomyName);
foreach($terms as $term) {
if ($term->parent != 0) { // пропускаем родительские категории
// здесь ваши инструкции
}
}
Я заметил, что у родительских категорий поле "parent" равно 0, а у дочерних категорий указан ID их родителя.

Принятый ответ выполняет N вызовов get_terms() и работает за полиномиальное время. Этот ответ выполняет единственный вызов get_terms() и работает за линейное время. Это гораздо лучший ответ.

@dotancohen Вы можете сделать это без необходимости исключать термины верхнего уровня при выводе, вы можете удалить термины верхнего уровня с помощью параметра wpse_exclude_top
, добавленного к аргументам запроса ;-). Однако я согласен, что этот ответ быстрее, чем принятый

@PieterGoosen: Спасибо, Pieter. Я только что проверил исходный код версии 4.4.2 на наличие строк wpse_exclude_top
и exclude_top
, но не нашел их. И Google тоже ничего не знает об этом. Где это задокументировано?

Мы можем исключить родительские элементы верхнего уровня, отфильтровав их с помощью фильтра terms_clauses
, чтобы изменить SQL-запрос перед его выполнением. Таким образом, нам не нужно пропускать родительские элементы в финальном цикле foreach
, так как их не будет в возвращаемом массиве терминов. Это избавляет нас от лишней работы и кода.
Можно попробовать следующий код:
add_filter( 'terms_clauses', function ( $pieces, $taxonomies, $args )
{
// Проверяем, установлен ли наш пользовательский аргумент и равен ли он 1, если нет — выходим
if ( !isset( $args['wpse_exclude_top'] )
|| 1 !== $args['wpse_exclude_top']
)
return $pieces;
// Если всё в порядке, удаляем родительские элементы
$pieces['where'] .= ' AND tt.parent > 0';
return $pieces;
}, 10, 3 );
Теперь, чтобы исключить родительские элементы верхнего уровня, мы можем передать параметр 'wpse_exclude_top' => 1
в массиве аргументов. Новый параметр wpse_exclude_top
поддерживается фильтром выше.
$terms = get_terms( 'category', ['wpse_exclude_top' => 1] );
if ( $terms
&& !is_wp_error( $terms )
) {
echo '<ul>';
foreach ($terms as $term) {
echo '<li><a href="' . get_term_link( $term ) . '">' . $term->name . '</a></li>';
}
echo '</ul>';
}
Небольшое замечание: функция get_term_link()
не принимает название термина, только его slug, ID или полный объект термина. Для производительности всегда передавайте объект термина в get_term_link()
, если он доступен (как в данном случае).

Привет, есть идеи как решить эту проблему? stackoverflow.com/q/70327174/9036446

установка аргумента childless
в true означает, что вы можете углубиться только на 1 уровень, поэтому это не работает для таксономий с 3 или более уровнями.

Если вам нужно отобразить несколько дочерних элементов родительского элемента, попробуйте этот способ. Отображает дочерние термины по указанным ID терминов.
$termIds = array(367, 366, 365, 364, 363, 362);
$taxonomyName = "age";
$args = array(
'orderby' => 'term_id',
'order' => 'DESC',
'hide_empty' => false,
'childless' => false,
);
$terms = get_terms( $taxonomyName, $args );
if ( ! empty( $terms ) && ! is_wp_error( $terms ) ){
$inc = 1;
foreach ( $terms as $term ) {
if (in_array($term->parent, $termIds)) {
echo '<option value="'.$term->term_id.'"><font><font>'.$term->name.'</font></font></option>';
}
}
}

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