How to hide an item from a menu to logged out users (without a plugin)
-
23-04-2021 - |
Question
I want to hide an item from a menu if a user is logged out.
I am currently using the below code that achieves this using two separate menus, but to save duplication, I would like to only have to manage one nav menu.
function my_wp_nav_menu_args( $args = '' ) {
if ( is_user_logged_in() ) {
$args['menu'] = 'logged-in';
} else {
$args['menu'] = 'logged-out';
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'my_wp_nav_menu_args' );
Is it possible to hide just one item for a logged out user, rather than doing it the way I currently am?
Solution
Find the class or id of the menu item that you want to hide.
suppose the class of that menu is logged-in-menu
Then in header.php file of your theme before closing head tag use the below code
<style>
<?php if(! is_user_logged_in() ) : ?>
.logged-in-menu{
display: none;
}
<?php endif; ?>
</style>
OTHER TIPS
As @chrisguitarguy already added a more than valid answered while I was writing this answer, here's a simple addition to the other two answers.
The return
value of the wp_setup_nav_menu()
function has a filter, which has $menu_item
as only value provided – exactly before it is returned – and it is of type object
and a \stdClass
with the following public
properties that you can check against:
ID
: The term_id if the menu item represents a taxonomy term.attr_title
: The title attribute of the link element for this menu item.classes
: The array of class attribute values for the link element of this menu item.db_id
: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist).description
: The description of this menu item.menu_item_parent
: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise.object
: The type of object originally represented, such as "category," "post", or "attachment."object_id
: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories.post_parent
: The DB ID of the original object's parent object, if any (0 otherwise).post_title
: A "no title" label if menu item represents a post that lacks a title.target
: The target attribute of the link element for this menu item.title
: The title of this menu item.type
: The family of objects originally represented, such as "post_type" or "taxonomy."type_label
: The singular label used to describe this type of menu item.url
: The URL to which this menu item points.xfn
: The XFN relationship expressed in the link of this menu item._invalid
: Whether the menu item represents an object that no longer exists.
So a simple callback will allow you to use some conditional logic and then maybe exclude an item:
add_filter( 'wp_setup_nav_menu', function( \stdClass $item ) {
# Check conditionals, and invalidate an item in case
$item->_invalid = is_user_logged_in()
&& 'post' === $item->object
&& 'post_type' === $item->type
# && … whatever you need to check for your invalidation of an item
;
return $item;
} );
The exclusion logic lives inside the _invalid
property and is executed by the _is_valid_nav_menu_item( $item )
function that is a callback used when nav menu items are retrieved. It uses it inside a array_filter()
to reduce the number of items depending on this flag.
As extension to @MD Sultan Nasir Uddin solution: While a CSS only solution will work, goal should be to not even have the data in this request, in the database query and in the render pipeline. For a complete answer, here still is the how: Example using wp_add_inline_style()
to inline the styles and PHP heredoc syntax for readability:
<?php
/** Plugin Name: Hide menu items for logged in users */
# Add class:
add_filter( 'wp_nav_menu_args', function( Array $args ) {
if ( is_user_logged_in() )
$args['menu_class'] .= ' logged-in';
return $args;
} );
# Add inline styles
add_action( 'wp_enqueue_scripts', function() {
$styles = <<<STYLES
.logged-in .special-item {
display: none;
}
STYLES;
wp_add_inline_style( 'custom-style', $styles );
} );
You could probably just use the body
classes to find a logged-in
or similar class for a more specific target as well – instead of adding an additional class like above.
Filter wp_nav_menu_objects
. It will contain the sorted list of nav menu items to render. Have a look at wp_setup_nav_menu_item
for some properties you can use.
Here's a quick (untested) example.
add_filter( 'wp_nav_menu_objects', function( array $items, array $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 );
After that I make it done using css nth child the procedure is
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;
}
Thanks all of you for your effort :)
<?php
//Then in header.php file of your theme before closing head tag use the below code
//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("Welcome vistor")</script>';
}
?>