Tassonomia personalizzata, get_the_terms, elenco in ordine genitore > figlio

25 dic 2011, 22:21:36
Visualizzazioni: 25.1K
Voti: 10

Ho una tassonomia gerarchica personalizzata che posso visualizzare usando 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
        )

)

Questa tassonomia avrà sempre la seguente forma: Ordine (genitore) > Famiglia (figlio dell'Ordine) > Sotto-famiglia (figlio della Famiglia)

Esiste un modo rapido e semplice per visualizzare queste tassonomie nell'ordine corretto, in modo da poter stampare la seguente riga? Ordine: <ordine>, Famiglia: <famiglia>, Sotto-famiglia: <sotto-famiglia>

Grazie in anticipo

1
Commenti

Chi mi ha votato negativamente, potreste spiegare il perché?

turbonerd turbonerd
26 dic 2011 15:09:39
Tutte le risposte alla domanda 7
5

Probabilmente ci sono modi migliori per farlo, ma puoi sempre utilizzare tre semplici cicli foreach.

Ho scritto una funzione di esempio che svolge bene il lavoro e dovrebbe servirti come un buon punto di partenza:

function print_taxonomic_ranks( $terms = '' ){

    // controlla l'input
    if ( empty( $terms ) || is_wp_error( $terms ) || ! is_array( $terms ) )
        return;

    // imposta le variabili ID a 0 per un controllo facile 
    $order_id = $family_id = $subfamily_id = 0;

    // ottiene l'ordine
    foreach ( $terms as $term ) {
        if ( $order_id || $term->parent )
            continue;
        $order_id  = $term->term_id;
        $order     = $term->name;
    }

    // ottiene la famiglia
    foreach ( $terms as $term ) { 
        if ( $family_id || $order_id != $term->parent )
            continue;
        $family_id = $term->term_id;
        $family    = $term->name;
    }

    // ottiene la sottofamiglia
    foreach ( $terms as $term ) { 
        if ( $subfamily_id || $family_id != $term->parent ) 
            continue;
        $subfamily_id = $term->term_id;
        $subfamily    = $term->name;
    }

    // output
    echo "Ordine: $order, Famiglia: $family, Sottofamiglia: $subfamily";

}

Inseriscila nel tuo file functions.php e usala nei tuoi template in questo modo:

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

NOTA: Ciclare lo stesso array tre volte può sembrare un po' stupido, ma d'altra parte è una soluzione rapida e semplice che è facile da leggere, estendere e mantenere.

27 dic 2011 16:19:01
Commenti

Non potrei essere più in debito con te. È una risposta perfetta, e vorrei poterti dare più reputazione!! Se qualcuno passa da questo post, per favore +1 così Maugly può essere ricompensato quanto vorrei io :)

turbonerd turbonerd
27 dic 2011 16:23:02

Nessun problema. Sono contento di aver potuto aiutare :) Ho anche aggiornato il codice nella mia risposta e aggiunto un semplice controllo dell'input...

Michal Mau Michal Mau
27 dic 2011 17:10:41

Maugly, grazie per la tua risposta, è quasi esattamente quello che mi serviva - hai qualche idea su come usarlo con i link degli archivi ancora collegati ai termini? Grazie ancora

User User
24 gen 2012 05:55:07

@Adam Dai un'occhiata a get_term_link()

Michal Mau Michal Mau
24 gen 2012 12:36:31

E se il post ha due categorie genitore? Sto cercando di risolvere, ma mi sta richiedendo troppo tempo capirlo ancora.

Lucas Bustamante Lucas Bustamante
2 giu 2015 08:20:46
1

Argomento un po' vecchio ma penso sia ancora rilevante dato che è ancora una gran seccatura.

Sto usando questa funzione ricorsiva che prende due array come riferimenti. Creerà un array con la struttura: [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 );

// Registrerà gli array annidati di oggetti term.
error_log( print_r( $sorted_terms, true ) );

Questa è l'unica soluzione che ho trovato che mantiene gli oggetti term e funziona con qualsiasi livello di annidamento.

20 set 2016 15:25:54
Commenti

Ottima risposta, grazie. Ancora utile nel 2022! C'è un piccolo errore di sintassi con una mancata corrispondenza $this-> quando si chiama la funzione, ma la logica è perfetta

Ian Ian
7 apr 2022 17:18:01
4

Anche se l'approccio di Maugly sembra un po' più leggibile, eseguire un ciclo 3 volte sull'array non mi sembra corretto. Ecco quindi un altro approccio che potrebbe essere meno leggibile per alcuni ma funziona senza eseguire il ciclo 3 volte.

function print_taxonomy_ranks( $terms ) {
    // se terms non è un array o è vuoto, non procedere
    if ( ! is_array( $terms ) || empty( $terms ) ) {
        return false;
    }

    foreach ( $terms as $term ) {
        // se il termine ha un genitore, imposta il termine figlio come attributo nel termine genitore
        if ( $term->parent != 0 )  {
            $terms[$term->parent]->child = $term;   
        } else {
            // registra il termine genitore
            $parent = $term;
        }
    }

    echo "Ordine: $parent->name, Famiglia: {$parent->child->name}, Sottofamiglia: {$parent->child->child->name}";
}
28 dic 2011 10:58:36
Commenti

Ottimo lavoro! Sapevo che fosse possibile, ma all'epoca non riuscivo a capire come :) Mi piace la tua soluzione!

Michal Mau Michal Mau
24 gen 2012 14:34:23

Avviso di downvote: Creazione di un oggetto predefinito da un valore vuoto

Brad Dalton Brad Dalton
25 set 2020 13:32:36

@Dev potresti per favore spiegare meglio? Di quale oggetto stai parlando. Anche se è una risposta di 9 anni fa, mi piacerebbe sapere a quale oggetto ti riferisci

Hameedullah Khan Hameedullah Khan
27 set 2020 07:14:32

Questo è il messaggio di errore che ottengo durante il test. Non specifica quale oggetto.

Brad Dalton Brad Dalton
27 set 2020 07:35:10
2

Mi sono trovato in una situazione in cui un articolo poteva essere etichettato con più gruppi di categorie, e più figli all'interno di categorie genitore, quindi volevo che la mia gerarchia riflettesse questo. Volevo anche solo poche righe di codice:

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

In sostanza, dopo aver trovato il genitore di una categoria, lo sposta nell'oggetto genitore come figlio, e poi lo rimuove dalla sua posizione originale nell'array. Ho testato questo codice utilizzando più fratelli, figli e diversi livelli di categorie.

Spero che qualcun altro trovi utile questo codice nel caso stia cercando una guida logica piuttosto che un "plugin"!

8 lug 2013 17:57:46
Commenti

Puoi spiegare come usarlo?

Lucas Bustamante Lucas Bustamante
2 giu 2015 08:22:01

@LucasB Proverò a ricordare :P Abbiamo un post, e sappiamo che il suo $post->ID è $id e "department_categories" sarebbe la tassonomia.

Semplicemente ottiene tutti i termini associati al post e ristruttura l'array dei risultati per avere più senso gerarchico. Una volta ristrutturato, sei libero di visualizzarlo come preferisci.

Kaitlyn McDonald Kaitlyn McDonald
2 giu 2015 16:22:36
1

Ispirato dalla risposta di Michal Mau e dalla risposta di Manny Fleurmond, ecco la mia soluzione: Ho lo stesso problema di @Lucas Bustamante: cosa succede se il post ha due categorie genitore?

La mia soluzione è stata creare un altro array di oggetti, confrontando il term_id e verificando la chiave parent

function print_taxonomic_ranks( $terms ){

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

    $parent_terms = array();

    // ottieni solo i genitori
    foreach ( $terms as $term ) {
        if ($term->parent === 0) {
            $term->child = Array();
            $parent_terms[] = $term;
        }
    }

    // confronta e annida
    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;
                }
            }
        }
    }

    // mostra i risultati
    foreach ( $parent_terms as $term ) {

        // termine genitore
        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>';
    }
}

e apparirà qualcosa come questo:

ottieni termini in ordine genitore

Saluti!

7 apr 2020 01:36:45
Commenti

Il tag <span> non è stato chiuso alla fine del codice echo '.<span>' => echo '.</span>'

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

Grazie Maugly,

Ecco la mia versione modificata del tuo codice che include i permalink dei termini per chi ne avesse bisogno

function print_show_location( $terms = '' ){

// controllo dell'input
if ( empty( $terms ) || is_wp_error( $terms ) || ! is_array( $terms ) )
    return;

// imposta le variabili ID a 0 per un controllo più semplice 
$country_id = $state_id = $city_id = 0;

// ottieni il paese
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>';
}

// ottieni lo stato
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>';
}

// ottieni la città
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>';
}

// output
echo "$city, $state - $country";

}
25 gen 2012 03:10:23
0

Ci sono un paio di funzioni ricorsive che utilizzo a seconda delle esigenze. Entrambe richiedono la lista dei termini, un ID genitore di partenza e un array iniziale (generalmente vuoto) dove inserire la lista risultante.

PRIMA VERSIONE

$terms = [una lista di oggetti termini, usa get_terms o altro]
$ordered_terms = array(); // qui troverai i termini ordinati, dalla radice al figlio finale

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);
}

SECONDA VERSIONE

$term_ids = [dovrebbe essere una lista di ID nella forma child_id => parent_id]

// un modo rapido per ottenere questo tipo di lista è usare WP_Term_query, esempio:
//$terms_query = new WP_Term_Query(array(
//  'taxonomy' => 'product_categories'
//  ,'object_ids' => $post->ID
//  ,'hide_empty' => false
//  ,'fields' => 'id=>parent'
//));

$ordered_terms = array(); // qui troverai i termini ordinati, dalla radice al figlio finale

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);
}

TERZA VERSIONE

Questa non è mia, l'ho trovata da qualche parte, probabilmente qui o su stackoverflow. Questa è leggermente diversa nell'output, poiché genererà una lista di termini a cascata, con una sola radice, che ha una proprietà children, che conterrà il termine successivo con la sua proprietà children e così via..

// $ordered_terms dovrebbe essere un array vuoto come sopra

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