Cum să ascunzi un element din meniu pentru utilizatorii neautentificați (fără plugin)
Vreau să ascund un element din meniu dacă un utilizator nu este autentificat.
În prezent folosesc codul de mai jos care realizează acest lucru folosind două meniuri separate, dar pentru a evita duplicarea, aș dori să gestionez un singur meniu de navigare.
function my_wp_nav_menu_args( $args = '' ) {
if ( is_user_logged_in() ) {
$args['menu'] = 'autentificat';
} else {
$args['menu'] = 'neautentificat';
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'my_wp_nav_menu_args' );
Este posibil să ascund doar un singur element pentru un utilizator neautentificat, în loc să procedez în modul în care o fac în prezent?

Filtrează wp_nav_menu_objects
. Va conține lista sortată de elemente din meniul de navigare pentru randare. Consultă wp_setup_nav_menu_item
pentru unele proprietăți pe care le poți folosi.
Iată un exemplu rapid (netestat).
add_filter( 'wp_nav_menu_objects', function( array $items, object $args ) {
if ( 'someThemeLocation' !== $args->theme_location ) {
return $items;
}
return array_filter( $items, function( $item ) {
return '/user-specific-thingy' === $item->url
&& ! is_user_logged_in();
} );
}, 10, 2 );

În timp ce @chrisguitarguy a adăugat deja un răspuns mai mult decât valid în timp ce scriam acest răspuns, iată o simplă adăugare la celelalte două răspunsuri.
Valoarea de return
a funcției wp_setup_nav_menu()
are un filtru, care are $menu_item
ca singură valoare furnizată – exact înainte de a fi returnată – și este de tip object
și un \stdClass
cu următoarele proprietăți public
pe care le puteți verifica:
ID
: term_id dacă elementul de meniu reprezintă un termen de taxonomie.attr_title
: Atributul title al elementului de link pentru acest element de meniu.classes
: Matricea de valori ale atributului class pentru elementul de link al acestui element de meniu.db_id
: ID-ul din baza de date al acestui element ca obiect nav_menu_item, dacă există (0 dacă nu există).description
: Descrierea acestui element de meniu.menu_item_parent
: ID-ul din baza de date al nav_menu_item care este părintele acestui element de meniu, dacă există. 0 în caz contrar.object
: Tipul de obiect reprezentat inițial, cum ar fi "category", "post" sau "attachment".object_id
: ID-ul din baza de date al obiectului original pe care îl reprezintă acest element de meniu, de exemplu ID pentru postări și term_id pentru categorii.post_parent
: ID-ul din baza de date al obiectului părinte al obiectului original, dacă există (0 în caz contrar).post_title
: O etichetă "fără titlu" dacă elementul de meniu reprezintă o postare care nu are titlu.target
: Atributul target al elementului de link pentru acest element de meniu.title
: Titlul acestui element de meniu.type
: Familia de obiecte reprezentate inițial, cum ar fi "post_type" sau "taxonomy".type_label
: Eticheta singulară folosită pentru a descrie acest tip de element de meniu.url
: URL-ul către care indică acest element de meniu.xfn
: Relația XFN exprimată în link-ul acestui element de meniu._invalid
: Dacă elementul de meniu reprezintă un obiect care nu mai există.
Deci, un simplu callback vă va permite să folosiți o logică condițională și apoi poate să excludeți un element:
add_filter( 'wp_setup_nav_menu', function( \stdClass $item ) {
# Verificați condițiile și invalidați un element în caz
$item->_invalid = is_user_logged_in()
&& 'post' === $item->object
&& 'post_type' === $item->type
# && … orice altceva trebuie să verificați pentru invalidarea unui element
;
return $item;
} );
Logica de excludere se află în interiorul proprietății _invalid
și este executată de funcția _is_valid_nav_menu_item( $item )
care este un callback folosit când elementele de meniu sunt preluate. Aceasta o folosește în interiorul unui array_filter()
pentru a reduce numărul de elemente în funcție de acest flag.
Ca extensie la soluția lui @MD Sultan Nasir Uddin: În timp ce o soluție doar cu CSS va funcționa, scopul ar trebui să fie să nu aveți date în această cerere, în interogarea bazei de date și în pipeline-ul de randare. Pentru un răspuns complet, iată în continuare cum: Exemplu folosind wp_add_inline_style()
pentru a include stilurile inline și sintaxa heredoc PHP pentru lizibilitate:
<?php
/** Plugin Name: Ascunde elementele de meniu pentru utilizatorii autentificați */
# Adaugă clasă:
add_filter( 'wp_nav_menu_args', function( Array $args ) {
if ( is_user_logged_in() )
$args['menu_class'] .= ' logged-in';
return $args;
} );
# Adaugă stiluri inline
add_action( 'wp_enqueue_scripts', function() {
$styles = <<<STYLES
.logged-in .special-item {
display: none;
}
STYLES;
wp_add_inline_style( 'custom-style', $styles );
} );
Ați putea probabil să folosiți doar clasele body
pentru a găsi o clasă logged-in
sau similară pentru o țintă mai specifică – în loc să adăugați o clasă suplimentară ca mai sus.

După aceea, am reușit să o fac folosind CSS nth-child, procedura este următoarea:
add_action('wp_head','hide_menu');
function hide_menu() {
if ( is_user_logged_in() ) {
//
} else {
$output="<style> .menu li:nth-child(3) { display: none; } </style>";
}
echo $output;
}
Vă mulțumesc tuturor pentru efortul depus :)

Nu-mi place ideea de a ascunde elementele de meniu doar cu CSS, deoarece acestea ar rămâne vizibile folosind inspectorul de cod de pe pagină. Pentru cei care caută o metodă mai sigură de a elimina elementele de meniu, acest cod ar trebui să facă treaba:
În acest exemplu, doresc să elimin elementul de meniu "Descărcări" pentru orice utilizator care nu este autentificat.
add_filter( 'wp_nav_menu_objects', 'remove_menu_items' ), 10, 2 );
function remove_menu_items( $items, $args ) {
// Dacă trebuie să elimini mai multe elemente de meniu, este o practică bună să setezi o variabilă pentru verificare în prealabil, astfel încât să nu rulezi aceeași funcție de verificare în mod repetat.
$logged_in = is_user_logged_in();
foreach ( $items as $item_index => $item ) {
// Elimină elementul de meniu "Descărcări" când utilizatorul nu este autentificat
if ( $item->title == 'Descărcări' ) {
if ( !$logged_in ) {
unset($items[$item_index]);
}
}
}
return $items;
}

Bazat pe răspunsul lui @jamio, sunt de acord că dacă doar folosești display:none
pentru meniu, acesta rămâne accesibil prin inspect element
. Prin urmare, am venit cu o soluție prin care poți ascunde elementele din meniu bazându-te pe clasa lor, folosind classes[0]
în loc de title
. Astfel, poți adăuga pur și simplu o clasă pe elementul de meniu în loc să-l setezi individual prin cod.
add_filter( 'wp_nav_menu_objects', 'remove_menu_items', 10, 2 );
function remove_menu_items( $items, $args ) {
$logged_in = is_user_logged_in();
foreach ( $items as $item_index => $item ) {
// Elimină elementul de meniu cu clasa "hide_when_logout" când utilizatorul nu este autentificat
if ( $item->classes[0] == 'hide_when_logout' ) {
if ( !$logged_in ) {
unset($items[$item_index]);
}
}
}
return $items;
}

<?php
//Apoi în fișierul header.php al temei tale, înainte de închiderea tag-ului head, folosește următorul cod
//https://wordpress.stackexchange.com/questions/233667/how-to-hide-an-item-from-a-menu-to-logged-out-users-without-a-plugin
<?php
if ( is_user_logged_in() ) {
$output="<style>.menu-item-8685 {display: none !important;}</style>";
echo $output;
} else {
echo '<script>alert("Bun venit vizitator")</script>';
}
?>

Găsește clasa sau ID-ul elementului de meniu pe care dorești să-l ascunzi.
presupunem că clasa acelui meniu este logged-in-menu
Apoi, în fișierul header.php al temei tale, înainte de închiderea tag-ului head, folosește următorul cod
<style>
<?php if(! is_user_logged_in() ) : ?>
.logged-in-menu{
display: none;
}
<?php endif; ?>
</style>

Aceasta înseamnă că (a) interogați date inutile și (b) este ireversibil pentru temele copil sau plugin-uri. Ați putea dori să folosiți cel puțin un callback atașat la wp_head
sau să înregistrați și să încărcați corect stilurile. Chiar dacă atunci ar fi o soluție întrucâtva acceptabilă, ar fi totuși de preferat să dezactivați condiționat acele elemente înainte de a le interoga din baza de date.

Pentru oricine se gândește să folosească acest lucru, vă rog să nu o faceți. Folosiți hook-urile corecte pentru meniu conform răspunsului lui @chrisguitarguy.
