I’m looking for ways to prevent “private” and “draft” pages from appearing (to non-logged-in admins) in a site’s Primary Navigation menu which is based on a custom menu – other than manually removing such pages from the WP custom menu and then dragging them back when they are published, that is.
FWIW, I’m surprised the behavior I’m looking for isn’t the default.
Using: WP 3.4.2
I had a similar problem and here is the best solution I could come up with. The reason (I think) that private or non-published items show up in menus is that the menu items are themselves posts and have their own
post_status
. That means that in a situation where a page is marked private, the menu item for that page can still be set to publish, and is displayed. I wrote a filter callback for thewp_nav_menu_objects
hook which looks at thepost_status
for the object that the menu item stands for, and removes it from the menu if that object is private. In my case, private pages was the concern, but one can easily adapt this for drafts. I also allow the menu items to be displayed if the user is logged in, whatever his capabilities are, whereas WP by default limits access to a private page to administrators and editors. This also can easily be adapted.It seemed to me easier and more appropriate to filter the menu items than to hide them with CSS, your milage may vary.
To limit menu items for private pages to administrators and editors you should be able to substitute
current_user_can ('read_private_pages')
for!is_user_logged_in ()
.I used this as a solution for hiding draft pages. You can hide the (draft page) menu items with the li.draft class.
FWIW: I feel the same way 😉
The easiest solution is to add a specific class to the menu items that you want to hide. And then hide them through CSS.
^ click to enlarge ^
The CSS classes are not visible by default, you have to enable it in the
Screen Options
upper tab.If your theme does not print the relevant classes in the
<body>
tag, this will do:Finally, in your
style.css
, add this rule:Another option, use the following filter:
“Manipulate the output” seems simple but reveals to be tricky:
<li>
with certain class attrHiding them with CSS is problematic, as they still get sent over the wire and still expose what could be sensitive information to anyone who looks at the source, to those who disable CSS for whatever reason (e.g. blind users — CSS just slows them down to no real benefit), and to hacker scripts and the like.
No, we need a way to allow menu items to be added to a menu that reference a page or post, but to only show or even send those menu items over the wire if the page or post to which they refer has been fully and publicly Published. Not Draft, not Pending, not Private, not Scheduled (until the scheduled time has passed), and certainly not Trashed.
Here’s a solution I found at another place which I modified slightly (add to theme’s
functions.php
):It would be much better to make one call to the database instead of multiple queries, especially if the menu has several items.
Based on some of the other answers you could build a list of approved ids and filter the items with that. Please note that the array declarations are PHP7.0+
Ok guys, Im here to give the best answer. This should be in WordPress core by now but I guess they have more important things to deal with.
The top rated answer from 2015 is good, but the below code is better in that it uses the wp_get_nav_menu_items function to retrieve all menu items of a navigation menu. Also, there is no need to check if !is_user_logged_in if you want a menu item hidden…you’re just making people waste time doing an incognito search if they’re logged in. Also, there is no need to do a search on the database