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.
functions.php
or an extremely large plugin does not slow down your site.