0

I have a theme which automatically adds all published pages to the menu. Is there a way to override this and add some of the pages only when the user is logged in? I thought maybe there is a filter for the menu, but could not find anything that works. Note that we are talking about frontend menu and pages here and I installed the Kadence theme. Maybe some of the themes does not support this, I have no idea...

What I have already tried so far is add_filter() with:

  • wp_nav_menu_items
  • wp_nav_menu_objects
  • wp_nav_menu_args
  • nav_menu_link_attributes

None of these filters are applied by building the menu as far as I can tell...

Looks like its the theme's default menu....

Turns out all of these work if I add a new menu to the theme. With the default menu none of them works. I'll report this as a bug to Kadence theme developers, I am curious about their opinion.

3
  • So, by default, WordPress registered menus will load all pages until you create a menu and manually add the pages you want, then assign it to the menu location. This isn't a bug, this is sort of the intentional method of making sure there's navigation. Commented Mar 26 at 1:34
  • @TonyDjukic It's ok, but if there is a default menu, then why don't add the usual hooks to it? I don't think it would be that hard to do it. If this is not a Kadence bug, then I'll send a feature request about it to WP developers.
    – inf3rno
    Commented Mar 26 at 8:52
  • Yeah, but it really does boil down to what the developer is thinking. Your best option is what you said here, send them a feature request or check in with the support team in case they have a solution in place already that works in a different manner than you expect. Commented Mar 26 at 12:30

2 Answers 2

0

You could use something like this:

// Function to hide menu items for non-logged-in users
function hide_menu_items_for_non_logged_in($items, $args) {
    // Check if user is not logged in
    if (!is_user_logged_in()) {
        // Define menu items to hide 
        // (replace 'menu-item-1', 'menu-item-2', etc. with actual menu item IDs)
        $items_to_hide = array('menu-item-1', 'menu-item-2');
        
        // Loop through menu items
        foreach ($items as $key => $item) {
            // Check if the current item is in the list of items to hide
            if (in_array($item->ID, $items_to_hide)) {
                // Remove the item from the menu
                unset($items[$key]);
            }
        }
    }
    
    return $items;
}

// Hook the function into the 'wp_nav_menu_items' filter
add_filter('wp_nav_menu_items', 'hide_menu_items_for_non_logged_in', 10, 2);

You could also use a CSS class that turns off display for specific items in the above loop; something like:

        if (in_array('hide-for-non-logged-in', $item->classes)) {
            // Add a custom CSS class to the item
            $item->classes[] = 'hide-item';
        }

Then adding that 'hide-item' CSS to your 'Additional CSS'.

1
  • The $items is a HTML string in the case of this filter...
    – inf3rno
    Commented Mar 25 at 20:38
0

Turns out all of these work if I add a new menu to the theme. With the default menu none of them works. I'll report this as a bug to Kadence theme developers, I am curious about their opinion.

For now I use the following code to hide my custom pages:

$page = get_posts([
    'meta_key' => 'my_frontend_id',
    'meta_value' => $this->id,
    'post_type' => 'page',
    'post_status' => 'any',
    'numberposts' => 1
])[0];
if (is_null($page)){
    $pageId = wp_insert_post($this->settings);
    add_post_meta($pageId, 'my_frontend_id', $this->id, true);
}
else
    $pageId = $page->ID;


add_filter('wp_nav_menu_objects', function ($items, $args) use ($pageId) {
   if (!is_user_logged_in())
        foreach ($items as $key => $item)
            if ($item->object_id == $pageId)
                unset($items[$key]);
   return $items;
}, 10, 2);

Note that the $pageId is integer here and the $item->object_id is string. I have no idea why WP is changing types. Maybe better to convert both to string and use === instead of using == to avoid misunderstandings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.