Как перечислить только термины таксономии для детей, а не их родителей?

9

Я создаю меню выбора возраста в администраторе, заполненный из таксономии 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аргументом, но он не принимает более 1 родительский идентификатор. Вот что я пока показываю, где показывают детей от 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, но я не уверен, как ее использовать, так как похоже, что она принимает только одно значение. Например: в этом примере будет построен неупорядоченный список, но я могу изменить меню выбора.

<?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>';
?> 
Эндрю
источник
Вызовите get_termsдважды и объедините два массива результатов?
Марк Дункан
@Mark Спасибо, я думал о том, чтобы сделать это таким образом, но даже если я объединю идентификаторы в массив, я не вижу, как это будет работать, потому что это будет то же самое, что перечислять их вручную - 183, 184, что не так. т работа.
Андрей
Прочитав принятый ответ, я теперь понимаю, что ваш вопрос не совсем ясен, судя по тому, что вы хотели, все термины, за исключением терминов верхнего уровня ... (что вы можете сделать с помощью одного get_termsзвонка). Ваш вопрос читается так, как будто вы хотите, чтобы у всех детей были два конкретных родительских термина.
Марк Дункан,

Ответы:

14

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

$taxonomyName = "age";
//This gets top layer terms only.  This is done by setting parent to 0.  
$parent_terms = get_terms( $taxonomyName, array( 'parent' => 0, 'orderby' => 'slug', 'hide_empty' => false ) );   
echo '<ul>';
foreach ( $parent_terms as $pterm ) {
    //Get the Child terms
    $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, работал удовольствие. Я взял то, что вы предоставили, и втирал это в меню выбора, которое мне было нужно. Качественный товар.
Андрей
Нет проблем. Рад, что это сработало для вас.
Мэнни Флермонд
1
Смотрите ответ karimhossenbux ниже для более эффективного ответа.
dotancohen
$term->nameнедействителен в get_term_link(), он принимает только термин ID, слизняк или объект
Питер Гусен
14

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

$terms = get_terms($taxonomyName);
foreach($terms as $term) {
    if ($term->parent != 0) { // avoid parent categories
        //your instructions here
    }
}

Я заметил, что у родителя есть поле «родителя», равное 0, и у ребенка есть его родительский идентификатор в нем.

karimhossenbux
источник
4
Принятый ответ выполняет N вызовов get_terms () и выполняется за полиномиальное время. Этот ответ запускает один вызов get_terms () и выполняется за линейное время. Это гораздо лучший ответ.
dotancohen
@dotancohen Вы можете сделать это, не исключая термины верхнего уровня при выводе, вы можете удалить термины верхнего уровня с помощью wpse_exclude_topпараметра, добавленного к аргументам запроса ;-). Однако я согласен, что это быстрее, чем принятый ответ
Питер Гусен
1
@PieterGoosen: Спасибо, Питер. Я просто скопировал исходный код 4.4.2 для строк wpse_exclude_topи exclude_topне нашел их. Google не знает об этом. Где это задокументировано?
dotancohen
1
@dotancohen в моем ответе ;-)
Питер Гусен
5

Мы можем исключить родителей верхнего уровня, отфильтровав их с помощью terms_clausesфильтра, чтобы изменить запрос SQL перед его выполнением. Таким образом, нам не нужно пропускать родителей в последнем foreachцикле, поскольку они не находятся в возвращаемом массиве терминов, это избавляет нас от ненужной работы и кодирования

Вы можете попробовать следующее:

add_filter( 'terms_clauses', function (  $pieces, $taxonomies, $args )
{
    // Check if our custom arguments is set and set to 1, if not bail
    if (    !isset( $args['wpse_exclude_top'] ) 
         || 1 !== $args['wpse_exclude_top']
    )
        return $pieces;

    // Everything checks out, lets remove parents
    $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()не принимайте только термин, имя, слаг, ID или полный термин объекта. Для производительности всегда передавайте термин «объект», get_term_link()если термин «объект» доступен ( как в этом случае )

Питер Гусен
источник
2

Почему вы не можете просто установить childlessаргумент в true?

$ages = get_terms( array(
    'taxonomy' => 'age',
    'childless' => true
    )
);
Ярон
источник
установка childlessаргумента в значение true означает, что вы можете углубиться только на 1 уровень, поэтому это не работает для таксономий с 3 и более уровнями.
GeckoSEO
-1

Если вы отображаете ребенка с несколькими родителями, вы можете попробовать это. Отобразить упомянутое имя

$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>';
    }
  }
}
Якир Хоссейн
источник
1
Пожалуйста, объясните, почему вы думаете, что этот код должен работать. Кроме того, я уверен, что жестко запрограммированное решение - не лучший способ.
s_ha_dum
Вопрос упоминается с идентификаторами, по этой причине я ответил, что думаю.
Якир Хоссейн