Taxonomie personalizată, get_the_terms, listare în ordinea părinte > copil

25 dec. 2011, 22:21:36
Vizualizări: 25.1K
Voturi: 10

Am o taxonomie ierarhică personalizată pe care o pot afișa folosind print_r(get_the_terms( $post->ID, 'taxonomic_rank' ));:

Array
(
    [46] => stdClass Object
        (
            [term_id] => 46
            [name] => Aplocheilidae
            [slug] => aplocheilidae
            [term_group] => 0
            [term_taxonomy_id] => 53
            [taxonomy] => taxonomic_ranks
            [description] => 
            [parent] => 39
            [count] => 1
            [object_id] => 443
        )

    [47] => stdClass Object
        (
            [term_id] => 47
            [name] => Aplocheilus
            [slug] => aplocheilus
            [term_group] => 0
            [term_taxonomy_id] => 54
            [taxonomy] => taxonomic_ranks
            [description] => 
            [parent] => 46
            [count] => 1
            [object_id] => 443
        )

    [39] => stdClass Object
        (
            [term_id] => 39
            [name] => Cyprinodontiformes
            [slug] => cyprinodontiformes
            [term_group] => 0
            [term_taxonomy_id] => 52
            [taxonomy] => taxonomic_ranks
            [description] => 
            [parent] => 0
            [count] => 1
            [object_id] => 443
        )

)

Această taxonomie va avea întotdeauna următoarea structură: Ordin (părinte) > Familie (copil al Ordinului) > Sub-familie (copil al Familiei)

Există o modalitate rapidă și ușoară de a afișa aceste taxonomii în ordinea corectă, astfel încât să pot afișa următoarea linie? Ordin: <ordin>, Familie: <familie>, Sub-familie: <sub-familie>

Mulțumesc anticipat

1
Comentarii

Cine m-a notat negativ, poți te rog să explici de ce?

turbonerd turbonerd
26 dec. 2011 15:09:39
Toate răspunsurile la întrebare 7
5

Probabil există modalități mai bune de a face acest lucru, dar poți folosi întotdeauna trei bucle simple foreach.

Am scris o funcție exemplu care face treaba bine și ar trebui să-ți servească ca punct de plecare bun:

function print_taxonomic_ranks( $terms = '' ){

    // verifică datele de intrare
    if ( empty( $terms ) || is_wp_error( $terms ) || ! is_array( $terms ) )
        return;

    // setează variabilele ID la 0 pentru verificare ușoară
    $order_id = $family_id = $subfamily_id = 0;

    // obține ordinul
    foreach ( $terms as $term ) {
        if ( $order_id || $term->parent )
            continue;
        $order_id  = $term->term_id;
        $order     = $term->name;
    }

    // obține familia
    foreach ( $terms as $term ) { 
        if ( $family_id || $order_id != $term->parent )
            continue;
        $family_id = $term->term_id;
        $family    = $term->name;
    }

    // obține subfamilia
    foreach ( $terms as $term ) { 
        if ( $subfamily_id || $family_id != $term->parent ) 
            continue;
        $subfamily_id = $term->term_id;
        $subfamily    = $term->name;
    }

    // afișează rezultatul
    echo "Ordin: $order, Familie: $family, Subfamilie: $subfamily";

}

Păstrează această funcție în fișierul tău functions.php și folosește-o în șabloanele tale astfel:

print_taxonomy_ranks( get_the_terms( $post->ID, 'taxonomic_rank' ) );

NOTĂ: Parcurgerea aceluiași array de trei ori poate părea puțin stupidă, dar pe de altă parte este o soluție rapidă și ușoară care este ușor de citit, extins și întreținut.

27 dec. 2011 16:19:01
Comentarii

Nu aș putea fi mai îndatorat față de tine. Acesta este un răspuns perfect și mi-aș dori să-ți pot oferi mai multă reputație!! Dacă cineva trece pe lângă acest post, te rog să îi dai +1, astfel încât Maugly să fie recompensat așa cum mi-aș dori eu :)

turbonerd turbonerd
27 dec. 2011 16:23:02

Nicio problemă. Mă bucur că am putut ajuta :) Am actualizat și codul din răspunsul meu și am adăugat o simplă verificare a input-ului...

Michal Mau Michal Mau
27 dec. 2011 17:10:41

Maugly, îți mulțumesc pentru răspuns, este aproape exact ceea ce aveam nevoie - ai vreo sugestie despre cum să-l folosesc cu link-urile de arhivă încă atașate termenilor? Mulțumesc din nou

User User
24 ian. 2012 05:55:07

@Adam Aruncă o privire la get_term_link()

Michal Mau Michal Mau
24 ian. 2012 12:36:31

Ce se întâmplă dacă postarea are două categorii părinte? Încerc să rezolv problema, dar îmi ia prea mult timp să o înțeleg momentan.

Lucas Bustamante Lucas Bustamante
2 iun. 2015 08:20:46
1

Tema puțin învechită, dar încă relevantă, cred eu, deoarece încă reprezintă o adevărată provocare.

Folosesc această funcție recursivă care primește două array-uri ca referințe. Va crea un array cu structura: [term_id] => term_object->children->child_terms_array->children->child_terms_array.

<?php
function sort_terms_hierarchically( array &$terms, array &$into, $parent_id = 0 ) {
    foreach ( $terms as $i => $term ) {
        if ( $term->parent == $parent_id ) {
            $into[$term->term_id] = $term;
            unset( $terms[ $i ] );
        }
    }

    foreach ( $into as $top_term ) {
        $top_term->children = array();
        $this->sort_terms_hierarchically( $terms, $top_term->children, $top_term->term_id );
    }

}

$terms = get_the_terms( 'taxslug', $post );
$sorted_terms = array();
sort_terms_hierarchically( $terms, $sorted_terms );

// Va afișa array-urile imbricate ale obiectelor termeni.
error_log( print_r( $sorted_terms, true ) );

Aceasta este singura soluție pe care am găsit-o vreodată care menține obiectele termenilor și funcționează cu orice nivel de imbricare.

20 sept. 2016 15:25:54
Comentarii

Răspuns excelent, mulțumesc. Încă util în 2022! Există o mică eroare de sintaxă cu un $this-> nepotrivit la apelarea funcției, dar logica este perfectă

Ian Ian
7 apr. 2022 17:18:01
4

Deși abordarea lui Maugly pare puțin mai ușor de citit, rularea unei bucle de 3 ori peste array nu mi se pare corectă. Așadar, iată o altă abordare care poate fi mai puțin lizibilă pentru unii, dar funcționează fără a rula bucla de 3 ori.

function print_taxonomy_ranks( $terms ) {
    // dacă termenii nu sunt un array sau este gol, nu continua
    if ( ! is_array( $terms ) || empty( $terms ) ) {
        return false;
    }

    foreach ( $terms as $term ) {
        // dacă termenul are un părinte, setează termenul copil ca atribut în termenul părinte
        if ( $term->parent != 0 )  {
            $terms[$term->parent]->child = $term;   
        } else {
            // înregistrează termenul părinte
            $parent = $term;
        }
    }

    echo "Ordine: $parent->name, Familie: {$parent->child->name}, Sub-Familie: {$parent->child->child->name}";
}
28 dec. 2011 10:58:36
Comentarii

Bună treabă! Știam că este posibil, dar nu mi-am putut da seama cum atunci :) Îmi place soluția ta!

Michal Mau Michal Mau
24 ian. 2012 14:34:23

Avertisment Downvote: Crearea unui obiect implicit dintr-o valoare goală

Brad Dalton Brad Dalton
25 sept. 2020 13:32:36

@Dev poți, te rog, să detaliezi? Despre ce obiect vorbești. Deși răspunsul are 9 ani, aș dori să știu la ce obiect te referi

Hameedullah Khan Hameedullah Khan
27 sept. 2020 07:14:32

Acesta este mesajul de eroare pe care îl primesc la testare. Nu specifică care obiect.

Brad Dalton Brad Dalton
27 sept. 2020 07:35:10
2

Am avut o situație în care un articol putea fi etichetat cu mai multe grupuri de categorii și mai multe subcategorii în cadrul categoriilor părinte, așa că am vrut ca ierarhia mea să reflecte acest lucru. Am vrut doar câteva linii de cod:

$terms = get_the_terms($id, 'department_categories');
foreach($terms as $key => $term){
    if($term->parent != 0){
        $terms[$term->parent]->children[] = $term;
        unset($terms[$key]);
    }
}

Practic, după ce găsește părintele unei categorii, o mută în obiectul părinte ca fiind un copil și apoi o elimină din poziția inițială din array. Am testat acest lucru folosind mai multe categorii de același nivel, subcategorii și niveluri diferite de categorii.

Sper că altcineva va găsi acest lucru util în cazul în care caută doar o îndrumare logică și nu un "plugin"!

8 iul. 2013 17:57:46
Comentarii

Poți să explici te rog cum să folosesc asta?

Lucas Bustamante Lucas Bustamante
2 iun. 2015 08:22:01

@LucasB O să încerc să-mi amintesc :P Avem un post și știm că $post->ID este $id și "department_categories" ar fi taxonomia.

Pur și simplu obține toți termenii asociați postului și restructurează array-ul de rezultate pentru a avea mai mult sens ierarhic. Odată restructurat, poți să-l afișezi cum consideri potrivit.

Kaitlyn McDonald Kaitlyn McDonald
2 iun. 2015 16:22:36
1

Inspirat de răspunsul lui Michal Mau și răspunsul lui Manny Fleurmond, iată soluția mea: Am aceeași problemă ca @Lucas Bustamante: Ce se întâmplă dacă postarea are două categorii părinte?

Soluția mea a fost să creez un alt array de obiecte, comparând term_id și verificând cheia parent

function print_taxonomic_ranks( $terms ){

    if ( ! is_array( $terms ) || empty( $terms ) ) {
        return false;
    }

    $parent_terms = array();

    // obține doar părinții
    foreach ( $terms as $term ) {
        if ($term->parent === 0) {
            $term->child = Array();
            $parent_terms[] = $term;
        }
    }

    // compară și imbrichează
    foreach ( $terms as $term ) {
        if ($term->parent != 0) {
            foreach ($parent_terms as $key => $value) {
                if ($term->parent === $value->term_id) {
                    $parent_terms[$key]->child[] = $term;
                }
            }
        }
    }

    // afișează rezultatele
    foreach ( $parent_terms as $term ) {

        // termen părinte
        echo '<span class="d-block">'.$term->name.'';

        if ($term->child) {
            $i = 1;
            foreach ( $term->child as $child ) {
                //echo '<span class="text-danger">'.$i.'</span>';
                echo ($i <= 1)? ": " : "";
                echo '<span class="font-weight-normal">'.$child->name.'</span>';
                echo ($i < count($term->child))? ", " : "";
            $i++;                
            }          
        }
        echo '.<span>';
    }
}

și va arăta cam așa:

obține termenii în ordinea părinților

Noroc!

7 apr. 2020 01:36:45
Comentarii

Tag-ul <span> nu a fost închis la sfârșitul codului echo '.<span>' => echo '.</span>'

Mahdi Afzal Mahdi Afzal
3 feb. 2021 15:13:14
0

Mulțumesc Maugly,

Iată versiunea mea modificată a codului tău care include termenii de legături permanente dacă cineva are nevoie

function print_show_location( $terms = '' ){

// verifică input-ul
if ( empty( $terms ) || is_wp_error( $terms ) || ! is_array( $terms ) )
    return;

// setează variabilele ID la 0 pentru verificare ușoară 
$country_id = $state_id = $city_id = 0;

// obține țara
foreach ( $terms as $term ) {
    if ( $country_id || $term->parent )
        continue;
    $country_id  = $term->term_id;
    $country_slug = $term->slug;
    $country = '<a href="'.get_term_link($country_slug, 'location').'">'.$term->name.'</a>';
}

// obține statul/județul
foreach ( $terms as $term ) { 
    if ( $state_id || $country_id != $term->parent )
        continue;
    $state_id = $term->term_id;
    $state_slug = $term->slug;
    $state = '<a href="'.get_term_link($state_slug, 'location').'">'.$term->name.'</a>';
}

// obține orașul
foreach ( $terms as $term ) { 
    if ( $city_id || $state_id != $term->parent ) 
        continue;
    $city_id = $term->term_id;
    $city_slug = $term->slug;
    $city = '<a href="'.get_term_link($city_slug, 'location').'">'.$term->name.'</a>';
}

// afișează
echo "$city, $state - $country";

}
25 ian. 2012 03:10:23
0

Există câteva funcții recursive pe care le folosesc în funcție de nevoile mele. Ambele necesită lista de termeni, un ID de părinte de pornire și un array de pornire (în general gol) în care să pun lista rezultată.

PRIMA VERSIUNE

$terms = [o listă de obiecte termeni, folosește get_terms sau orice altceva]
$ordered_terms = array(); // aici vei găsi termenii ordonați, de la rădăcină la ultimul copil

function list_terms_by_parent($parent_id = 0, &$terms, &$ordered_terms){
  $root_parent = $parent_id;

  foreach($terms as $index => $term){
    if($term->parent == (int) $parent_id){
      $ordered_terms[$term->term_id] = $term;
      $root_parent = $term->term_id;
      unset($terms[$index]);
    }
  }

  if(!empty($terms)) list_terms_by_parent($root_parent, $terms, $ordered_terms);
}

A DOUA VERSIUNE

$term_ids = [ar trebui să fie o listă de ID-uri în forma child_id => parent_id]

// o metodă rapidă de a obține acest tip de listă este să folosești WP_Term_query, exemplu:
//$terms_query = new WP_Term_Query(array(
//  'taxonomy' => 'product_categories'
//  ,'object_ids' => $post->ID
//  ,'hide_empty' => false
//  ,'fields' => 'id=>parent'
//));


$ordered_terms = array(); // aici vei găsi termenii ordonați, de la rădăcină la ultimul copil

function list_term_ids_by_parent($parent_id = 0, &$term_ids, &$ordered_terms){
  $child_id = array_search($parent_id, $term_ids);

  if($child_id){
    $ordered_terms[] = $child_id;
    unset($term_ids[$child_id]);
  }

  if(!empty($term_ids)) order_terms($child_id, $term_ids, $ordered_terms);
}

A TREIA VERSIUNE

Aceasta nu este a mea, am găsit-o undeva, probabil aici sau pe stackoverflow. Aceasta este puțin diferită la ieșire, deoarece va genera o listă de termeni în cascadă, cu o singură rădăcină, care are o proprietate children, care va conține următorul termen cu proprietatea sa children și așa mai departe..

// $ordered_terms se presupune că este un array gol ca mai sus

function sort_terms_hierarchically(&$terms, &$ordered_terms, $parentId = 0){
  foreach($cats as $i => $cat){
    if($cat->parent == $parentId){
      $into[$cat->term_id] = $cat;
      unset($cats[$i]);
    }
  }

  foreach ($into as $topCat) {
    $topCat->children = array();
    sort_terms_hierarchically($cats, $topCat->children, $topCat->term_id);
  }
}
18 nov. 2019 13:47:32