Skip to main content
deleted 38 characters in body
Source Link
kaiser
  • 50.8k
  • 27
  • 150
  • 244
add_filter( 'wp_setup_nav_menu', function( \stdClass $item ) {
    # Check conditionals, and invalidate an item in case
    if ( 
      $item->_invalid = is_user_logged_in() 
        && 'post' === $item->object
        && 'post_type' === $item->type
        # && … whatever you need to check for your invalidation of an item
    )
        $item->_invalid = TRUE;;

    return $item;
} );
add_filter( 'wp_setup_nav_menu', function( \stdClass $item ) {
    # Check conditionals, and invalidate an item in case
    if ( 
        is_user_logged_in() 
        && 'post' === $item->object
        && 'post_type' === $item->type
        # && … whatever you need to check for your invalidation of an item
    )
        $item->_invalid = TRUE;

    return $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;
} );
Source Link
kaiser
  • 50.8k
  • 27
  • 150
  • 244

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
    if ( 
        is_user_logged_in() 
        && 'post' === $item->object
        && 'post_type' === $item->type
        # && … whatever you need to check for your invalidation of an item
    )
        $item->_invalid = TRUE;

    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.