Evidențierea clasei strămoș wp_nav_menu() fără copii în structura de navigare
(Notă moderatori: Titlul original era "Clasa strămoș wp_nav_menu fără copii în structura de navigare")
Am un wp_nav_menu
în header care conține trei pagini. Când mă aflu pe una dintre aceste pagini, elementul li
care conține acea pagină în meniu primește clasa .current_page_item
. Aceste trei pagini au șabloane, iar aceste șabloane conțin interogări personalizate pentru a obține toate postările de un anumit tip de conținut. În esență, "copiii" percepuți ai acestei pagini de nivel superior nu sunt de fapt copii, ci sunt doar de un tip de conținut pe care l-am asociat cu acea pagină de nivel superior folosind un șablon.
Aș dori ca elementele de meniu de nivel superior să primească o clasă 'current-ancestor'
când utilizatorul navighează pe o pagină individuală a unui tip specific de postare, din nou, asociată cu acea pagină doar într-o interogare personalizată din fișierul șablon.
Sper că are sens - dacă nu, spuneți-mi unde v-am pierdut! Apreciez foarte mult orice ajutor.
--Editat pentru specificații: De exemplu, am o pagină statică numită Workshops care folosește un șablon. Slug-ul său este workshops. Șablonul are o funcție personalizată get_posts și o buclă în interiorul său, care extrage și afișează toate postările de un tip de conținut personalizat numit workshops. Dacă fac clic pe titlul unuia dintre aceste workshop-uri, sunt dus la conținutul complet al acelei bucăți de conținut. Structura permalink-ului pentru tipul de postare personalizat este setată la workshops/postname, astfel încât din perspectiva utilizatorului, aceste bucăți de conținut sunt copii ai paginii Workshops, când în realitate sunt toate de un singur tip de conținut dar nerelaționat cu pagina. Acest decalaj trebuie să-l închid efectiv în meniu, evidențiind elementul de meniu 'Workshops' când navighez prin conținut de tip 'workshop'.
Din nou, sper că are sens, cred că am spus 'workshop' de peste 20 de ori într-un singur paragraf!

Există o soluție mai simplă. Uitați de crearea de pagini pentru fiecare tip de postare doar pentru a avea elemente în meniul de navigare, deoarece, așa cum ați învățat, WP nu are nicio modalitate de a recunoaște că tipurile personalizate pe care le vizualizați sunt legate de acea pagină.
În schimb, creați o legătură personalizată în Aspect->Meniuri. Pur și simplu introduceți URL-ul care va returna tipul dvs. personalizat și dați-i o etichetă, apoi apăsați "Adaugă în meniu".
http://example.com/workshops/
sau pentru permalink-uri neoptimizate:
http://example.com/?post_type=workshops
doar acest lucru va crea un buton de navigare care afișează toate postările cu acel tip de postare personalizată și va adăuga și clasa current-menu-item când ați dat clic pe acel element de navigare - dar nu va încă adăuga clasa de navigare pe orice alt URL decât acesta
Apoi, odată creat, accesați configurația pentru acel element nou și introduceți slug-ul tipului de postare personalizată în câmpul "Atribut Titlu" (ați putea folosi și câmpul de descriere, dar acesta este ascuns în opțiunile ecranului de administrare în mod implicit).
Acum, trebuie să conectați filtrul nav_menu_css_class
(care este declanșat pentru fiecare element de navigare) și să verificați dacă conținutul vizualizat este de tipul indicat în elementul dvs. personalizat de navigare:
add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
$post_type = get_query_var('post_type');
if ($item->attr_title != '' && $item->attr_title == $post_type) {
array_push($classes, 'current-menu-item');
};
return $classes;
}
În acest caz, vom verifica dacă conținutul câmpului Atribut Titlu nu este gol și dacă se potrivește cu post_type curent care este interogat. Dacă da, adăugăm clasa current-menu-item la matricea sa de clase, apoi returnăm matricea modificată.
Ați putea modifica acest lucru pentru a se potrivi pur și simplu cu titlul elementului de navigare, dar dacă dintr-un motiv oarecare doriți să denumiți elementul de navigare diferit de slug-ul simplu al tipului de postare, utilizarea câmpului Atribut Titlu sau Descriere vă oferă această flexibilitate.
Acum, ori de câte ori vizualizați un singur element (sau probabil chiar și liste de arhivă) ale unui tip de postare care se potrivește cu un element din meniul de navigare, acel element va primi clasa CSS current-menu-item, astfel încât evidențierea dvs. să funcționeze.
Nu sunt necesare pagini sau șabloane de pagini ;-) Interogarea URL se ocupă de preluarea postărilor corecte. Șablonul dvs. de buclă se ocupă de afișarea rezultatului interogării. Această funcție se ocupă de recunoașterea a ceea ce este afișat și de adăugarea clasei CSS.
BONUS
Puteți chiar automatiza procesul folosind wp_update_nav_menu_item
, prin generarea automată a elementelor de meniu pentru toate tipurile dvs. de postări. Pentru acest exemplu, ar trebui mai întâi să obțineți $menu_id
al meniului de navigare în care doriți să adăugați aceste elemente.
$types = get_post_types( array( 'exclude_from_search' => false, '_builtin' => false ), 'objects' );
foreach ($types as $type) {
wp_update_nav_menu_item( $menu_id, 0, array(
'menu-item-type' => 'custom',
'menu-item-title' => $type->labels->name,
'menu-item-url' => get_bloginfo('url') . '/?post_type=' . $type->rewrite['slug'],
'menu-item-attr-title' => $type->rewrite['slug'],
'menu-item-status' => 'publish'
)
);
}

Exact asta! Folosesc șabloane de pagină doar pentru că layout-urile sunt destul de complexe pentru acele pagini și nu doar listează paginile, dar tot pot folosi filtrul pe care l-ai oferit pentru a verifica ID-ul paginii. Natura acestui temă este că opțiunile de temă te ajută să asociezi paginile ('acasă' este această pagină, 'despre' este această pagină, etc.), așa că ar trebui să funcționeze perfect. Mulțumesc pentru ajutorul (incredibil de detaliat)!

a trebuit să elimin current_page_parent
din elementul de navigație care era blogul meu - dar în rest a funcționat. mersi

nu a funcționat pentru mine, deoarece $item->attr_title
extragea TITLUL, iar eu am scris titlul cu litere mari. așa că am schimbat atributul în $item->post_name
și acum funcționează perfect pentru mine.

în loc să folosești
$post_type = get_query_var('post_type');
Ai putea încerca:
$post_type = get_post_type();
Uneori tipul de postare nu este setat în variabila de interogare. Acesta este cazul pentru tipul implicit de postare "post", așa că dacă vrei să evidențiezi o postare care a fost listată dintr-o pagină de listare, va trebui să folosești această funcție. get_query_var() returnează doar un șir gol pentru tipurile de postare care nu sunt personalizate.
add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
$post_type = get_post_type();
if ($item->attr_title != '' && $item->attr_title == $post_type) {
array_push($classes, 'current-menu-item');
};
return $classes;
}

@Somatic - asta e fantastic! Am modificat puțin codul tău ca să funcționeze și pentru o Taxonomie specifică (pe care o folosesc doar pentru post_type-ul asociat). Ideea este să folosim atributul Title al elementului de meniu pentru a stoca atât numele post_type-ului CÂT și numele taxonomiei, separate prin punct și virgulă, care apoi sunt explodate de funcție.
add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
# obținere variabile din interogare
$post_type = get_query_var('post_type');
$taxonomy = get_query_var('taxonomy');
# obținere și parsare atribut Title din Meniu
$title = $item->attr_title; // atributul Title al elementului de meniu, ca post_type;taxonomy
$title_array = explode(";", $title);
$title_posttype = $title_array[0];
$title_taxonomy = $title_array[1];
# adăugare clasă dacă e necesar
if ($title != '' && ($title_posttype == $post_type || $title_taxonomy == $taxonomy)) {
array_push($classes, 'current-menu-item');
};
return $classes;
}

Iată soluția mea dacă doriți să lucrați cu wp_list_pages.
Adăugați acest cod în fișierul functions.php
add_filter('page_css_class', 'my_page_css_class', 10, 2);
function my_page_css_class($css_class, $page){
$post_type = get_post_type();
if($post_type != "page"){
$parent_page = get_option('page_for_custom_post_type-'.$post_type);
if($page->ID == $parent_page)
$css_class[] = 'current_page_parent';
}
return $css_class;
}
Acum adăugați în tabelul wp_options un nou rând cu un option_name de tipul page_for_custom_post_type-xxxx și o option_value cu ID-ul paginii pe care doriți să o conectați.
Probabil ați observat că există deja o opțiune numită page_for_posts. Dacă aveți un singur tip de postare personalizată, puteți seta pagina în /wp-admin/options-reading.php în meniul derulant și navigația va seta corect current_page.
Cred că nucleul WordPress ar trebui să extindă această secțiune cu un meniu derulant pentru fiecare tip de postare înregistrat.

Am decis să folosesc pagini și să utilizez numele șablonului de pagină ca clasă pe elementul de navigație. Acest lucru îmi permite să evit aglomerarea atributului title, ceea ce nu mi-a plăcut la alte soluții.
add_filter('nav_menu_css_class', 'mbudm_add_page_type_to_menu', 10, 2 );
// Dacă un element de meniu este o pagină, adaugă numele șablonului ca clasă CSS
function mbudm_add_page_type_to_menu($classes, $item) {
if($item->object == 'page'){
$template_name = get_post_meta( $item->object_id, '_wp_page_template', true );
$new_class =str_replace(".php","",$template_name);
array_push($classes, $new_class);
return $classes;
}
}
De asemenea, am adăugat clase pentru body în header.php
<body <?php body_class(); ?>>
În final, această soluție necesită CSS suplimentar pentru a aplica starea de selectat/activ pe elementele din meniul de navigație. O folosesc pentru a afișa arhivele de taxonomii și tipurile personalizate de postări legate de pagină ca elemente copil ale acestei pagini:
/* stări selectate - include subpagini pentru orice legat de produse */
#nav-main li.current-menu-item a,
body.single-mbudm_product #nav-main li.lp_products a,
body.tax-mbudm_product_category #nav-main li.lp_products a,
#nav-main li.current_page_parent a{color:#c00;}

Aceasta mi-a dat următoarea eroare:
Warning: join() [function.join]: Invalid arguments passed in /home/path/to/wp-includes/nav-menu-template.php on line 76
Ai vreo idee ce s-a întâmplat aici?

@Somatic - Cod excelent! Am făcut o mică modificare personală. Am dorit să păstrez Atributul Title pentru scopul său inițial, așa că am plasat slug-ul Custom Post Type în Link Relationship (XFN) din proprietățile avansate ale meniului, care pot fi activate în Screen Options. Am modificat
if ($item->attr_title != '' && $item->attr_title == $post_type) {
și l-am schimbat în
if ($item->xfn != '' && $item->xfn == $post_type) {

Bună treabă, Somatic.
Din păcate, nu înțeleg cum poți lista tipurile tale personalizate de postări într-o pagină așa cum explici. Dacă nu folosesc o pagină page-portfolio.php și o adaug într-o pagină, primesc doar eroarea 404.
Dacă procedez ca Gavin, am modificat puțin funcția ta pentru a elimina și clasa "current_page_parent" din pagina de blog, astfel:
add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2);
function current_type_nav_class($css_class, $item) {
$post_type = get_query_var('post_type');
if (get_post_type()=='portfolio') {
$current_value = "current_page_parent";
$css_class = array_filter($css_class, function ($element) use ($current_value) { return ($element != $current_value); } );
}
if ($item->attr_title != '' && $item->attr_title == $post_type) {
array_push($css_class, 'current_page_parent');
};
return $css_class;
}
