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?

Was it helpful?

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>';
    }
     ?>
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top