Taxonomie personalizată, get_the_terms, listare în ordinea părinte > copil
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

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.

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 :)

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...

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

@Adam Aruncă o privire la get_term_link()

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.

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

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

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

@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

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"!

@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.

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:
Noroc!

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

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