Как вывести только дочерние элементы таксономии без их родительских элементов?

24 июл. 2011 г., 15:51:21
Просмотры: 94.2K
Голосов: 12

Я создаю меню выбора возраста в админке, заполняемое из таксономии 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>';
?> 
3
Комментарии

Вызывать get_terms дважды и объединить два массива результатов?

t31os t31os
24 июл. 2011 г. 18:21:36

@Mark Спасибо, я думал сделать так, но даже если объединить ID в массив, я не понимаю, как это сработает, потому что это будет то же самое, что перечислить их вручную - 183, 184, что не работает.

Andrew Andrew
25 июл. 2011 г. 02:43:27

Прочитав принятый ответ, я теперь понимаю, что ваш вопрос был не совсем ясен. Похоже, вы хотели получить все термины, исключая термины верхнего уровня.. (что можно сделать одним вызовом get_terms). Ваш вопрос звучал так, будто вы хотели получить всех потомков двух определенных родительских терминов..

t31os t31os
26 июл. 2011 г. 19:03:00
Все ответы на вопрос 6
4
19

Это должно сработать для вас:

$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>';
25 июл. 2011 г. 06:46:05
Комментарии

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

Andrew Andrew
25 июл. 2011 г. 07:57:08

Без проблем. Рад, что всё сработало.

Manny Fleurmond Manny Fleurmond
25 июл. 2011 г. 08:21:17

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

dotancohen dotancohen
15 мар. 2016 г. 18:47:22

$term->name недопустим в get_term_link(), функция принимает только ID термина, его slug или объект

Pieter Goosen Pieter Goosen
15 мар. 2016 г. 20:03:04
4
17

Вы также можете сделать так:

$terms = get_terms($taxonomyName);
foreach($terms as $term) {
    if ($term->parent != 0) { // пропускаем родительские категории
        // здесь ваши инструкции
    }
}

Я заметил, что у родительских категорий поле "parent" равно 0, а у дочерних категорий указан ID их родителя.

15 мар. 2016 г. 18:32:03
Комментарии

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

dotancohen dotancohen
15 мар. 2016 г. 18:46:41

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

Pieter Goosen Pieter Goosen
15 мар. 2016 г. 20:05:07

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

dotancohen dotancohen
16 мар. 2016 г. 10:23:06

@dotancohen в моём ответе ;-)

Pieter Goosen Pieter Goosen
16 мар. 2016 г. 10:24:53
1

Мы можем исключить родительские элементы верхнего уровня, отфильтровав их с помощью фильтра 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(), если он доступен (как в данном случае).

15 мар. 2016 г. 20:01:59
Комментарии

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

evavienna evavienna
17 дек. 2021 г. 07:22:10
3

Почему нельзя просто установить аргумент childless в значение true?

$ages = get_terms( array(
    'taxonomy' => 'age',
    'childless' => true
    )
);
20 окт. 2016 г. 02:20:19
Комментарии

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

GeckoSEO GeckoSEO
23 апр. 2018 г. 18:58:19

Это идеально подошло для моих нужд! Спасибо!

jsmod jsmod
11 окт. 2020 г. 19:54:13

Также это вернёт родителей без детей вместо детей без родителей.

certainlyakey certainlyakey
2 янв. 2021 г. 23:15:05
0
$taxonomy = 'age';
foreach( get_terms( [ 'taxonomy' => $taxonomy, 'parent' => 0 ] ) as $parent )
{
    foreach( get_terms[ 'taxonomy' => $taxonomy, 'parent' => $parent->term_id ] as $child )
    {
        // выполняем действия
        print_r( $child );
    }
}
16 апр. 2024 г. 13:16:09
2
-1

Если вам нужно отобразить несколько дочерних элементов родительского элемента, попробуйте этот способ. Отображает дочерние термины по указанным 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>';
    }
  }
}
29 дек. 2015 г. 15:16:42
Комментарии

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

s_ha_dum s_ha_dum
29 дек. 2015 г. 16:23:58

В вопросе упоминаются идентификаторы, поэтому я дал ответ, связанный с этой темой.

Jakir Hossain Jakir Hossain
30 дек. 2015 г. 17:23:33