Excluderea dinamică a elementelor din meniul wp_nav_menu
Am încercat să caut informații despre cum să exclud/elimin elemente din meniurile personalizate, și singurul thread pe care l-am găsit nu avea răspunsuri utile pentru mine.
1. Context:
Am creat un meniu Dock folosind meniurile personalizate WP (wp_nav_menu) și jqDock pe site-ul meu. Deoarece jqDock are nevoie de imagini continue sau linkuri cu imagini pentru a funcționa, folosesc un walker personalizat astfel încât output-ul HTML al meniului să arate așa:
<div id="menu-first" class="nav">
<a><img src="http://path/to/image-1.png"/></a>
<a><img src="http://path/to/image-2.png"/></a>
<a><img src="http://path/to/image-3.png"/></a>
etc...
</div>
Codul pentru walker-ul meu personalizat este:
class custom_nav_walker extends Walker_Nav_Menu
{
// Tipul arborelui de meniu
var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
function start_lvl(&$output, $depth) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class=\"sub-menu\">\n";
}
function end_lvl(&$output, $depth) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
$class_names = ' class="' . esc_attr( $class_names ) . '"';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
$id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';
//$output .= $indent . '<li' . $id . $value . $class_names .'>';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$description = ! empty( $item->description ) ? esc_attr( strtolower( $item->description )) : '';
$item_title = ! empty( $item->attr_title ) ? esc_attr( $item->attr_title ) : '';
if ( strpos($description, ';') !== false ) {
$description_array = explode (';', $description);
$image_name = $description_array[0];
$image_alt = $description_array[1];
} else {
$image_name = $description;
$image_alt = $item_title;
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before .'<img src="'.get_bloginfo('template_url').'/images/skin1/'.$image_name.'" alt="'.$image_alt.'" title="'.$item_title.'" />'.$args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
function end_el(&$output, $item, $depth) {
$output .= "";
}
}
Scriptul jqDock prinde apoi ID-ul meniului ('menu-first') și înlocuiește output-ul wp_nav_menu cu cel al meniului Dock. Output-ul HTML al meniului Dock se modifică în funcție de opțiunile specificate la încărcarea jqDock.
2. Întrebarea:
Aș dori să nu afișez (adică să exclud) anumite elemente din meniu în funcție de locul unde se află utilizatorul pe site. De exemplu, aș dori să afișez elementul Home doar când utilizatorul nu este pe pagina Home, și elementul Post aleatoriu doar când este.
3. Soluții respinse:
a. Meniuri multiple: Înregistrarea și crearea mai multor meniuri și apoi apelarea lor condițional ar putea funcționa; totuși, nu cred că este o soluție ideală sau curată din multe motive. De asemenea, meniurile multiple sunt dificil de întreținut sau actualizat.
b. Căutare și înlocuire Regex: Acest lucru m-ar putea forța să schimb parametrul needle de fiecare dată când schimb opțiunile jqDock deoarece output-ul HTML este modificat.
c. Proprietatea CSS 'display': Ascunderea elementelor prin proprietatea CSS display funcționează, dar deoarece trebuie aplicată output-ului meniului jqDock, afectează redarea vizuală a meniului.
4. Soluții eșuate:
a. Filtru pentru wp_nav_menu_items: Am încercat să prind variabila '$items' (string) și să-i atribui valori diferite prin tag-uri condiționale cu următorul cod:
function userf_dynamic_nav_menu ($items) {
$items_array_home = explode('<a', $items);
$items_array_nothome = $items_array_home;
unset($items_array_home[1]);
unset($items_array_nothome[2]);
$items_home = implode('<a', $items_array_home);
$items_nothome = implode('<a', $items_array_nothome);
if ( is_home() ) {
$items = $items_home;
} else {
$items = $items_nothome;
}
return $items;
}
add_filter('wp_nav_menu_first_items', 'userf_dynamic_nav_menu');
Aceasta funcționează doar parțial, deoarece elementele meniului se schimbă, dar tag-urile condiționale sunt ignorate. Presupun că acest lucru are sens din cauza momentului în care este aplicat filtrul.
b. Funcție meniu nav personalizată: Am încercat să creez propria funcție de meniu nav personalizată pentru a putea adăuga un argument exclude la array-ul $defaults și pentru a utiliza acest cod ușor modificat din wp_list_pages
pentru a popula argumentul suplimentar:
$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );
Aveți idei?
Metoda 1
Puteți adăuga un constructor la Walker-ul personalizat pentru a stoca argumente suplimentare de excludere, cum ar fi:
class custom_nav_walker extends Walker_Nav_Menu {
function __construct( $exclude = null ) {
$this->exclude = $exclude;
}
function skip( $item ) {
return in_array($item->ID, (array)$this->exclude);
// sau
return in_array($item->title, (array)$this->exclude);
// etc.
}
// ...în interiorul start_el, end_el
if ( $this->skip( $item ) ) return;
}
Sau omiteți constructorul și setați proprietatea $exclude
înainte de a-l transmite ca walker la wp_nav_menu()
astfel:
$my_custom_nav_walker = new custom_nav_walker;
$my_custom_nav_walker->exclude = array( ... );
În funcție de ce excludeți, furnizați forma corectă pentru excludere.
Metoda 2
Aceasta este modalitatea prin care ați putea realiza acest lucru prin conectarea la filtrul wp_get_nav_menu_items
.
function wpse31748_exclude_menu_items( $items, $menu, $args ) {
// Iterați prin elementele pentru a căuta și elimina
foreach ( $items as $key => $item ) {
if ( $item->object_id == 168 ) unset( $items[$key] );
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );
Notă: object_id
este obiectul la care meniul face referire, în timp ce ID
este ID-ul meniului, acestea sunt diferite.
Spuneți-mi părerea dumneavoastră.

Am încercat abordarea cu constructorul și, indiferent ce fac, primesc constant eroarea "Tip de date incorect pentru al doilea argument" pentru funcția in_array
. Fac ceva greșit?

Proprietatea $exclude
trebuie să fie un array. Deci asigură-te că transmiți un array în constructor, sau verifică codul actualizat în răspunsul meu. În special conversia de tip pentru $this->exclude
, pentru cazul în care nu este transmis un array.

Îmi cer scuze pentru asta: am avut o greșeală de tipar în funcția mea. Tocmai am încercat $exclude = array ('4', '7');
și folosind și slug-urile, dar nu are niciun efect asupra rezultatului walker-ului. Voi încerca a doua abordare și vă voi anunța.

Nu, nici asta nu a funcționat. Cred că mi-am epuizat creierul încercând să rezolv asta, așa că s-ar putea să-mi afecteze... "performanța", :-)

Ei bine, un lucru pe care s-ar putea să nu-l faci este să compari valoarea actuală $item
, amintește-ți că $item
este o clasă standard cu proprietăți, așa că trebuie să compari una dintre proprietățile sale cu orice furnizezi. Poți folosi var_dump
pe $item
pentru a vedea ce fel de proprietăți sunt disponibile pentru comparare atunci când excludi. Am editat codul meu pentru a-l face mai clar.

Cu metoda 2, elementele de meniu dispar și din Aspect > Meniuri în panoul de administrare. Cum poți evita acest lucru?

........Răspunsul este că ai nevoie de verificarea condițională is_admin() pentru a vedea dacă panoul de administrare este încărcat.

ajută asta
$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );
ca exemplu
<?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'exclude' => '66' ) ); ?>

Salut Saq, am uitat să menționez că una dintre soluțiile care nu a funcționat a fost crearea unei funcții personalizate nav_menu și adăugarea acelui cod ca argument suplimentar la valorile implicite ale funcției. Din păcate, nu a funcționat. Nu am încercat să o includ în walker, dar nu cred că ar funcționa nici asta din același motiv pe care l-am menționat mai sus, mai ales că wp_nav_menu
nu are un argument "exclude", dar aș putea greși.

Am actualizat postarea inițială pentru a include acest lucru pentru claritate.

ce-ar fi să nu folosești un walker personalizat, ci în schimb să folosești un nav_menu obișnuit și să extragi elementele cu wp_get_nav_menu_items() cu imaginea ta personalizată

Aceasta ar fi o soluție bună în general, dar în acest caz particular, wp_get_nav_menu_items
nu va prelua imaginile deoarece tag-urile img nu sunt stocate în meniul personalizat (doar numele fișierelor sunt în câmpul de descriere, de exemplu, "image1.png"). Walker-ul personalizat este ceea ce îmi permite să inserez tag-urile img în output-ul meniului.
