Make WordPress Core

Opened 16 years ago

Last modified 3 months ago

#13822 reopened defect (bug)

Menu items that get unpublished still appear

Reported by: nacin's profile nacin Owned by: nacin's profile nacin
Milestone: Future Release Priority: normal
Severity: normal Version: 3.0
Component: Menus Keywords: good-first-bug has-test-info has-patch
Focuses: Cc:

Description

We need to properly account for menu items linked to unpublished/pending post type objects.

My thought is they should probably be hidden from the frontend with an indication on the backend (like "(Pending)") that they are are unpublished/pending.

We need to properly handle private posts too.

Attachments (16)

13822.diff (1.6 KB) - added by wpmuguru 16 years ago.
A patch to kick around
sync-menu-item-status-to-orig-object.13822.diff (10.9 KB) - added by filosofo 16 years ago.
13822.2.diff (3.8 KB) - added by nacin 16 years ago.
13822-reverts-r15219.diff (14.8 KB) - added by nacin 16 years ago.
Would revert [15219].
13822-reverts-r15219.2.diff (16.5 KB) - added by koopersmith 16 years ago.
13822-reverts-r15219.3.diff (18.3 KB) - added by koopersmith 16 years ago.
generalize-object-change-logic.1.diff (1.1 KB) - added by filosofo 16 years ago.
13822-on-r15218.diff (9.1 KB) - added by nacin 16 years ago.
generalize-object-change-logic.2.diff (1.1 KB) - added by filosofo 16 years ago.
13822.merged.diff (6.5 KB) - added by koopersmith 16 years ago.
13822.logic.and.trash.diff (3.6 KB) - added by koopersmith 16 years ago.
13822.labels.diff (1.6 KB) - added by koopersmith 16 years ago.
13822.original.link.diff (1.5 KB) - added by koopersmith 16 years ago.
13822.reverts.diff (12.5 KB) - added by nacin 15 years ago.
Reverts everything, removes trash handlers, revisit in 3.0.1.
13822.3.diff (3.3 KB) - added by wonderboymusic 13 years ago.
13822.4.diff (4.0 KB) - added by wonderboymusic 12 years ago.

Download all attachments as: .zip

Change History (75)

#1 @filosofo
16 years ago

  • Owner set to filosofo
  • Status changed from new to accepted

@wpmuguru
16 years ago

A patch to kick around

#2 @wpmuguru
16 years ago

That patch takes the menu item out on both the front end and in the menu editor. I didn't test, but I expect if the user saves the menu, the menu item would be removed. That's not ideal but is better than putting out a link that will 404.

#3 @nacin
16 years ago

  • Severity changed from normal to major

We don't want to remove pending/draft posts from the admin, I don't think. When I discussed this with Jane, appending a label like "(Draft)" (which could probably cover both) in the admin would be the best solution.

Then we can just skip over non-published posts in the front end.

Do we want to ignore posts that become private? I say skip right over them, assuming they have to be publicly published to show up in the admin.

This is somewhat edge, as it only 404's the link and I don't think we allow non-published posts to be added in the first place, so its status will have to change after the fact. However, it does reveal some information about the post.

Considered a blocker for RC3.

#4 @filosofo
16 years ago

  • Version set to 3.0

Got an idea for implementing the "(Draft)" label, and working on a patch.

#5 @filosofo
16 years ago

  • Keywords has-patch added

sync-menu-item-status-to-orig-object.13822.diff does the following:

  • Renames _wp_auto_add_pages_to_menu to _wp_menu_changing_status_observer and uses it to catch parent object status changes in addition to new top-level page publishing.
  • Makes what we've been calling "pending" menu items actually have "pending" status instead of "draft" (duh?)
  • If an associated post object becomes "draft" from "publish," the menu item gets "draft" status.
  • If an associated post object becomes "publish" from "draft" (re-published), the menu item is re-published too.
  • Pending menu items behave the same as before.
  • Draft menu items' statuses are tied to their associated post objects; in other words, unlike pending menu items, saving the menu does not change a menu item's status from "draft" to "publish."

#6 @wpmuguru
16 years ago

  • Resolution set to fixed
  • Status changed from accepted to closed

(In [15219]) hide unpublished items on frontend nav menus, props filosofo, fixes #13822

#7 follow-up: @nacin
16 years ago

  • Keywords dev-feedback added; has-patch removed
  • Priority changed from normal to highest omg bbq
  • Resolution fixed deleted
  • Status changed from closed to reopened

I'm seeing some issues with [15219].

Listening for status changes is not very effective, as you can't easily account for all options.

The commit does not account for pending, private, or scheduled posts, only draft posts. Additionally, the menu item is only triggered back to publish again when it goes straight from draft to publish. It might very well pass through pending or scheduled on the way to publish.

I liked wpmuguru's take, though not the patch, and had tried to patch this in wp_setup_nav_menu_item() because we pull the post object and could easily check if the post status is not "publish," and then exclude it from the menu. Unfortunately, the way we call wp_setup_nav_menu_item() (through array_map) means we can't simply unset the item, and since we map arrays through wp_setup_nav_menu_item like a dozen places, we'd have to make a lot of changes.

We could pair array_map() calls with array_filter(), and return null from wp_setup_nav_menu_item(), but that's not very DRY. I think at this point that's our best case scenario however, as it is a minimal code change, and we would revert much of [15219].

#8 @nacin
16 years ago

  • Owner changed from filosofo to nacin
  • Status changed from reopened to reviewing

koopersmith and I are talking about this now, and we have two potential solutions we're both working on.

One is a variation of wpmuguru's patch, and the other is a variation of my initial approach. Both have the advantage of piggybacking on an existing get_post/get_posts call, and both would only be triggered when we want it (i.e. not in the admin).

@nacin
16 years ago

@nacin
16 years ago

Would revert [15219].

#9 @nacin
16 years ago

  • Keywords has-patch added

Patch from koopersmith and me reverts [15219] and makes some important changes to properly fix this ticket:

  • wp_nav_menu() now passes an argument to wp_get_nav_menu_items(), telling that function to use a wrapper for wp_setup_nav_menu_item(), which would then filter out unpublished posts, only on the frontend, and during menu display, not on any hooks.
  • Menu items that are associated with a post that is unpublished now gets a status after it, such as "(Draft)" and "(Pending)", using the post status object label.
  • "(Pending)" in non-JS becomes "(Unsaved)" because "Pending" is an existing status we also need to display. i18n-change, we're adding "%s (Unsaved)". Also, "Click Save Menu to make pending menu items public." becomes "Click Save Menu to make unsaved menu items public." (Redundant/obvious, but a yellow warning never hurt.)
  • Removes the trash/untrash post hooks and other special trash handling. They didn't work properly, as they should have returned the menu item to the end of the menu on untrash. Now, we handle it like other stati, i.e. "(Trash)". i18n-change, we're adding "Original: %1$s (%2$s)", that way we reflect the status here too.

This patch is scary -- there's a lot being changed, or so it seems. I think we should do this in pieces, at least two commits if not more. First, revert [15219], then fix frontend, labels, and trash. Once [15219] is out it'll look much more sane.

#10 @nacin
16 years ago

  • Keywords i18n-change added

#11 @markjaquith
16 years ago

This patch is scary -- there's a lot being changed, or so it seems. I think we should do this in pieces, at least two commits if not more. First, revert [15219], then fix frontend, labels, and trash. Once [15219] is out it'll look much more sane.

Agreed. Go ahead and do that.

#12 in reply to: ↑ 7 ; follow-up: @filosofo
16 years ago

Replying to nacin:

Listening for status changes is not very effective, as you can't easily account for all options.

The commit does not account for pending, private, or scheduled posts, only draft posts.

True, but it seems like the proposal changes a single-point logic failure into an extensive code rewrite. Fix the logic at the point of failure, instead.

Among my concerns:

  • This proposal rewrites lots of code to deal with a niche situation that has, at worst, a dead link as its consequence.
  • The problem can be better solved at object-change time (as it currently does):
    • When the associated object changes is the right time to change its associated menu item.
    • This proposal puts additional burdens on the public generation of menus, rather than handling the issue one time when it happens.
  • We should not be putting query logic into wp_setup_nav_menu_item, as this proposal does. wp_setup_nav_menu_item simply decorates an object to give it the requisite standard menu item properties.
    • This proposal takes wp_setup_nav_menu_item, a function that does one thing, and one thing well, and gives it additional things to do, which means the bug possibilities open up proportionally.
    • By having wp_setup_nav_menu_item handle additional arguments, it introduces the possibility of returning null having passed in an object, which doesn't make sense for something that's only supposed to add properties.
  • We should not be putting view logic into wp_get_nav_menu_items
    • It makes wp_get_nav_menu_items more complicated: instead of getting menu items and passing them to wp_setup_nav_menu_item to decorate them, the proposal has it determining view state ('public_consumption'). This is the wrong place for that logic.
  • r15219 also had logic simplification for auto-page-add. Those should not be reverted.

To re-iterate:

  • I think this can be handled more simply.
  • The potential problems of the status quo (in other words, dead menu links) do not warrant wholesale code change at this point.
  • This proposal involves a number of questionable design decisions with long-term implications.

Therefore I strongly object to these proposed changes.

#13 @filosofo
16 years ago

As as starting point, what are the current problems not solved by generalize-object-change-logic.1.diff?

#14 in reply to: ↑ 12 ; follow-up: @nacin
16 years ago

Dead link is not the only consequence, it is exposure of data that should be hidden.

I have attached a diff that shows my changes against r15218, which shows the limited changes of the diff (a lot of it is removing the specialized trash handling).

The patch you posted to get us going is missing the exclusion of $old_status == $new_status and also would probably duplicate efforts with trashing and untrashing of posts. The current implementation is not ideal UX, it overlapped with the no-JS pending, and triggered a bunch of bugs related to unpublished handling, starting with menu items associated with trashed posts. On the other hand, 13822-reverts-r15219.3.diff is ready for commit. I thought [15219] was way too many changes so deep into an RC phase, and additional bandaids on it now is probably the wrong direction.

Handling this on generation is exactly how wp_list_pages/wp_page_menu functions, in that its get_pages() call only grabs published pages. I fail to see any simplicity in generalize-object-change-logic.1.diff that is not present in 13822-on-r15218.diff, and it's hardly a code rewrite. It's more code changes and more points for failure than what's currently in core.

This proposal puts additional burdens on the public generation of menus, rather than handling the issue one time when it happens.

Absolutely not. It's extraordinarily light code.

wp_setup_nav_menu_item() decorates a menu object based on the properties of post object it is associated with. If the properties of the post object invalidate the menu item for public display, that is clearly within the definition of setting up the menu item. It opens up no additional "bug possibilities".

I think most of the concerns outlined here are exaggerated. Your suggestions of where logic needs to go is largesly based on opinion, and I largely disagree with the assumptions made here. Calling it "questionable design decisions with long-term implications" is laughable and reactionary, and I think we both know that.

Two tactics here: focusing on synchronizing object stati with menu items, and handling this on generation. I frankly don't care which we go with, though I feel handling this on public generation would be far more versatile.

#15 in reply to: ↑ 14 @filosofo
16 years ago

Replying to nacin:

The patch you posted to get us going is missing the exclusion of $old_status == $new_status

How would that affect the end result?

and also would probably duplicate efforts with trashing and untrashing of posts.

OK, so add a check for when the new status is "trash." No big deal.

The current implementation is not ideal UX, it overlapped with the no-JS pending, and triggered a bunch of bugs related to unpublished handling, starting with menu items associated with trashed posts.

Please list the bugs. I still haven't seen any specifics. Again, I fail to see why we can't handle trashed posts with a couple lines in the observer.

I thought [15219] was way too many changes so deep into an RC phase, and additional bandaids on it now is probably the wrong direction.

That seems like a non-sequitur: there were too many changes, so in response we should make even more substantial ones?

Handling this on generation is exactly how wp_list_pages/wp_page_menu functions, in that its get_pages() call only grabs published pages.

The point is that it's not necessary in the first place: no matter how minimal, we're doing logic checks for a niche situation on every menu generation, logic checks that don't need to be done there at all.

And other functions like wp_list_pages are not a helpful analogy, because here we're querying objects (menu items) that are not the same as the objects causing the problem (posts, pages, etc.).

I fail to see any simplicity in generalize-object-change-logic.1.diff that is not present in 13822-on-r15218.diff

In generalize-object-change-logic.1.diff I see about 3 lines changed, as opposed to the dozens of new lines, several significant API changes and logic branches added in 13822-on-r15218.diff.

This proposal puts additional burdens on the public generation of menus, rather than handling the issue one time when it happens.

Absolutely not. It's extraordinarily light code.

It may be feather-light, but it's a feather that doesn't need to be there in the first place.

wp_setup_nav_menu_item() decorates a menu object based on the properties of post object it is associated with. If the properties of the post object invalidate the menu item for public display, that is clearly within the definition of setting up the menu item.

Actually, that's mixing up "view" with "model." The proposed changes attempt to change an object's data to respond to an issue of its presentation.

It opens up no additional "bug possibilities".

Instead of passing one object as the argument, now the proposal wants to pass an $args variable that is meant to branch on presentation logic. Imagine trying to create unit tests each for the current and the proposed, and you'll get what I mean.

I think most of the concerns outlined here are exaggerated. Your suggestions of where logic needs to go is largesly based on opinion, and I largely disagree with the assumptions made here.

Although what's considered good programming practice has a large element of the subjective (perhaps judgment and experience) mixed in it, that doesn't mean that it's simply a matter of opinion. I'm not clever enough to have come up with MVC, Uncle Bob's "Single Responsibility Principle," or Unix's "do one thing and do it well."

Calling it "questionable design decisions with long-term implications" is laughable and reactionary, and I think we both know that.

I've already raised questions against the design decisions; the long-term implications are that we'll be stuck with more-complicated, logically-convoluted code.

I am reacting to what seems like a disproportionately large change, in RC3, for a trivial problem.

Nothing about this makes me want to laugh.

#16 @filosofo
16 years ago

No one's going to read the previous comment, so let me boil it down to this:

Assuming we add a check for trash status, what are the bugs that still occur against generalize-object-change-logic.1.diff applied?

#17 @filosofo
16 years ago

Try generalize-object-change-logic.2.diff

#18 follow-up: @koopersmith
16 years ago

13822.merged.diff merges filosofo's approach with the UX changes in nacin/my earlier patch. The following describes the UX changes and the reasoning behind their implementation.

Menu item titles now reflect their object's status.

Instead of reading "My Post (Draft)" for all non-published objects, titles now include their object's status, such as "My Post (Private)".

This improves UX by informing the user why their post will not appear in the menu (and as a result, what they can change to have the menu item appear). This is especially useful for scheduled posts, as it reflects the fact that the menu will dynamically update.

Trash behavior changes: On trash, make the menu item 'draft' instead of 'pending'.

The existing behavior is as follows:

  • Add post A to the menu. Save. Trash post A.
  • The menu item disappears from the frontend menu (as it should).
  • If post A is untrashed and the menu has not been edited, the menu item will be automatically restored to its original position.

However, we run into trouble when we edit the menu:

  • Post A appears as "Post A (Pending)". You can edit this menu item like you would any other menu item. There's even a yellow box that reads "Click Save Menu to make pending menu items public."
  • When you save the menu, you are simultaneously presented with a warning that "Post A" referred to a trashed item and could not be saved, and a notice that the menu has been updated. The trashed item has been removed.

There is no indication that the trashed item will be removed and no way for the user to recover the menu item. The fact that the item is labelled as "pending" only adds to the confusion.

A menu item linking to a trashed post is no different than a menu item linking to a draft post or a pending post. If a menu item is untrashed it should reappear in the frontend menu (much like a menu item linking to a private post would if made public).

In the backend, the item will now appear as "Post A (Trash)". If a user wants to delete the item, they will. If the user wants to rearrange the menu and untrash the post, they can do that too. We should not be making the decision to delete the menu item for them; we should be providing the information necessary for them to make a competent decision.

(The implementation involved removing the trash/untrash listeners as well as the clause that deleted any menu items with trashed objects when the menu was saved.)

Improve "Original: Link to post" box.

Finally, the "Original: Link to post" has been updated to reflect any non-published post status (such as "Original: Link to post (Draft)"). Linking to a trashed post would lead to a 404—instead, we link to the appropriate trash page.

#19 in reply to: ↑ 18 @filosofo
16 years ago

Replying to koopersmith:

13822.merged.diff

+1

I think you nailed it.

#20 @koopersmith
16 years ago

Divided the patch along the three features described in my previous comment.

#21 @nacin
16 years ago

  • Keywords ux-feedback added; dev-feedback removed

I'm quite happy to see this plan of attack worked out. Nice job.

Looks like we have one removed string, two changed strings, and two new strings. All are small changes it appears.

Appears good to commit. I want a sign-off from Jane on the "({post_status})" and "(Unsaved)" labels. We all appear to be in agreement that this is the best course of action.

#22 @nacin
16 years ago

(In [15249]) Treat trash/untrash of posts associated with media items the same as other stati changes. props koopersmith, see #13822.

#23 @nacin
16 years ago

  • Resolution set to fixed
  • Status changed from reviewing to closed

(In [15250]) Add admin UI labels for menu items of unpublished posts. props koopersmith, fixes #13822. #stringchange

#24 @jane
15 years ago

I thought we were done for 3.0. We're in RC3 with a planned launch for today. Why exactly are we suggesting changing something untested on the day of release that *no one considered a blocker as of last Thursday in the official dev chat when the dates were decided*?

#25 @markjaquith
15 years ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

I told Nacin to put the new patch in because there was already a fix in ( [15219] ) that wasn't quite cutting it. We had to move forward (fix it with a new patch) or backwards (yank the patch out and live with it as a known issue). They were eager to fix, so I wanted to give them a shot. I expected that it likely would have to be reverted. I wanted to see if they could come up with a relatively simple fix that we could ship for 3.0. What they came up with is good, but not simple. It doesn't seem like a simple fix is even possible. I'm chatting with Nacin now to talk about the "known issue" implications of backing away to make sure there are no gotchas.

#26 @filosofo
15 years ago

r15249 fixes the non-UX issues mentioned in this ticket, with no string changes, so it should stay at least.

@nacin
15 years ago

Reverts everything, removes trash handlers, revisit in 3.0.1.

#27 @nacin
15 years ago

http://core.trac.wordpress.org/attachment/ticket/13822/13822.reverts.diff reverts [15219] and [15250]. Keeps part of [15249], as in the trash handlers are now gone.

#28 @koopersmith
15 years ago

If we can keep r15249 (logic/trash), the bug should be fixed.
Reverting r15250 will remove the descriptive labels and cause the "Original:" link to objects in trash to 404.

If we revert to auto-add and nix the trash handlers (i.e. 13822.reverts.diff), users will just see some weird behavior with trash and won't know when a menu-item refers to a non-published item. And the frontend should just do its thing.

#29 @markjaquith
15 years ago

Yep. I think we can live with that for 3.0, and revisit your comprehensive solution for 3.0.1. It's the most conservative option we have available.

#30 follow-up: @filosofo
15 years ago

Why not keep all of r15249?

#31 in reply to: ↑ 30 ; follow-up: @nacin
15 years ago

Replying to filosofo:

Why not keep all of r15249?

Because we're also removing r15219. The last part of r15249 makes a change to code introduced in r15219. The parts that are "kept" in r15249 are the giant blocks of red removing the trash/untrash handlers.

#32 in reply to: ↑ 31 @filosofo
15 years ago

Replying to nacin:

Because we're also removing r15219.

Yes, but why? That was the question.

#33 @nacin
15 years ago

  • Keywords ux-feedback i18n-change removed

Too much too close to final release. We either need all of it in, or all of it out, so we're removing the whole bit and going to revisit in 3.0.1.

#34 @nacin
15 years ago

  • Milestone changed from 3.0 to 3.0.1

(In [15254]) Revert [15219], [15250], some of [15249] for 3.0, revisit in 3.0.1. see #13822.

#35 @koopersmith
15 years ago

Replying to markjaquith:

Yep. I think we can live with that for 3.0, and revisit your comprehensive solution for 3.0.1. It's the most conservative option we have available.

I agree. After testing the patch, it seems like the most lightweight option we have. Removing the trash handlers reduces numerous odd behaviors into one bug—if you give a menu an object, it will show it regardless of the object's status. This is much easier to understand from a user's perspective and is likely the best possible interim solution.

#36 @nacin
15 years ago

  • Priority changed from highest omg bbq to normal
  • Severity changed from major to normal

#37 @nacin
15 years ago

Closed #14054 as a duplicate.

#38 @filosofo
15 years ago

I think my patch on 13958 is another way of handling this same issue.

#39 @nacin
15 years ago

  • Keywords early added
  • Milestone changed from 3.0.1 to 3.1

#40 @nacin
15 years ago

  • Keywords 3.2-early added; early removed
  • Milestone changed from 3.1 to Future Release

#41 @nacin
14 years ago

This fixed with #13958?

#42 @marcus1060
13 years ago

This is still an issue in 3.4.1.
Really think that non-published articles should not show up even if in a menu.

#43 @wonderboymusic
13 years ago

  • Keywords needs-refresh added
  • Milestone changed from Future Release to 3.6

Doing some housekeeping here. Some of the code from 13822.merged.diff already made it into core. The pieces I could translate, I added in 13822.3.diff. There is a piece in wp-includes/nav-menu.php from 13822.merged.diff that belongs to a function that no longer exists. If anyone wants to do the archaeology there, please do.

#44 @helen
13 years ago

#23835 was marked as a duplicate.

#45 @wonderboymusic
12 years ago

  • Milestone changed from 3.6 to Future Release

this bowl of spaghetti still applies with some fuzz, but I have no idea what I did when I made the patch

#46 @wonderboymusic
12 years ago

  • Keywords needs-testing added; needs-refresh removed
  • Milestone changed from Future Release to 3.7

Needs a look by someone who knows the origin story here

#47 @nacin
12 years ago

  • Milestone changed from 3.7 to Future Release

Back to the Future.

#48 @chriscct7
10 years ago

  • Keywords 3.2-early removed

#49 @SergeyBiryukov
10 years ago

#33987 was marked as a duplicate.

#50 @dd32
9 years ago

#37164 was marked as a duplicate.

This ticket was mentioned in Slack in #core-test by hellofromtonya. View the logs.


5 years ago

#52 @SirLouen
5 months ago

  • Keywords good-first-bug needs-patch has-test-info added; has-patch needs-testing removed

Reproduction Report

Description

✅ This report validates whether the issue can be reproduced.

Environment

  • WordPress: 6.9-alpha-60093-src
  • PHP: 8.2.28
  • Server: nginx/1.29.0
  • Database: mysqli (Server: 8.4.5 / Client: mysqlnd 8.2.28)
  • Browser: Chrome 137.0.0.0
  • OS: Windows 10/11
  • Theme: Twenty Fifteen 4.0
  • MU Plugins: None activated
  • Plugins:
    • Classic Editor 1.6.7
    • Hello Dolly 9.7.2
    • Image Generator 1.1
    • Test Reports 1.2.0

Reproduction Instructions

  1. Create a Page and publish it
  2. Create a new Menu
  3. Add this Page created to the menu
  4. Unpublish the page to Pending Review Status
  5. Check the menu in the front-end
  6. 🐞 Page is still there showing

Expected Results

  • Page should disappear from menu when is not published (or menu should be checking if all links are active)

Actual Results

  1. ✅ Error condition occurs (reproduced).

Additional Notes

  • The issue is already happening, but released patches are not working. A full refresh is required. To add more traction given that the patch is not valid any more, I would wipe the has-patch, and set it as a fresh report.

This ticket was mentioned in PR #9192 on WordPress/wordpress-develop by @kush123.


5 months ago
#53

  • Keywords has-patch added; needs-patch removed

# Menu items that get unpublished still appear.

## Overview

This pull request updates the logic for rendering menu items in WordPress navigation menus. It ensures that only items linked to published posts or pages are displayed on the frontend, improving consistency and preventing dead links.

Previously, menu items tied to draft, pending, and private content would still appear on the frontend, leading to broken or inaccessible navigation links.

## Trac Ticket: #13822

---

## Issue Fixed

### Menu Items Linked to Unpublished Posts Still Show Publicly

  • Problem: Menu items remain visible on the frontend even when the linked post is no longer published (e.g., moved to trash or reverted to draft).
  • Solution: Updated the condition from checking only for 'trash' to checking whether the post's status is not equal to 'publish'. If so, the menu item is marked as invalid (_invalid = true) and excluded from the frontend display.

---

## Code Changes

### Previous behavior (only hiding trashed items)

if ( 'trash' === get_post_status( $menu_item->object_id ) ) {
    $menu_item->_invalid = true;
}

### Updated behavior (hides all non-published items)

if ( 'publish' !== get_post_status( $menu_item->object_id ) ) {
    $menu_item->_invalid = true;
}

This ensures the menu item is only considered valid when the linked object is in the 'publish' state.

---

## Admin Behavior

  • The admin menu editor already displays visual indicators for unpublished items, such as:
    • (Draft)
    • (Pending)
    • (Trash)
    • (Private)
  • A yellow notice such as: “Click Save Menu to make unsaved menu items public.” already informs users that certain items won't be visible on the live site.

No changes were made to the admin UI — it already handles this use case effectively.

---

## Testing Instructions

### Test Case: Hide Non-Published Menu Items

  1. Create a post or page and publish it.
  2. Add it to a navigation menu.
  3. View the frontend — the menu item should be visible.
  4. Edit the post and change its status to one of the following:
    • Draft
    • Pending Review
    • Private
    • Trashed
  5. Refresh the frontend.

#### Expected Results

  • The menu item is no longer shown on the frontend.
  • In the admin menu editor, the item:
    • Remains listed
    • Displays a status indicator such as “(Draft)” or “(Inactive)”
    • Shows a warning if needed

---

#54 @kush123
5 months ago

  • Keywords needs-testing added

#55 @websiteredev
5 months ago

Patch Test Report

This report validates that the indicated patch addresses the issue.

Patch tested: https://github.com/WordPress/wordpress-develop/pull/9201

Environment

  • OS: Windows 10 Build 19045
  • Web Server: PHP.wasm
  • PHP: 7.4.31
  • WordPress: 6.9-alpha-20250704.081141
  • Browser: Chrome Version 137
  • Theme: Twenty Twenty-Five 1.2
  • Active Plugins:
    • None

Steps

  1. Created a new post and published it
  2. Added post to navigation menu
  3. Viewed front end and confirmed new page was showing in navigation menu
  4. Edited post status to Draft
  5. Refreshed front end and confirmed new page was NOT showing in navigation menu ✅
  6. Refreshed navigation menu editor and confirmed new page is showing in navigation menu editor with "(Draft)" text after page title ✅

Actual Results

  • ✅ Issue resolved with patch.

#56 @oglekler
3 months ago

@audrasjb Can you please check this one? The patch looks straightforward and makes a lot of sense. From my point of view, it is really annoying when you have menu links to unpublished pages.

#57 @peterwilsoncc
3 months ago

There's a little work to be done on the patch.

The patch assumes that only items with the post status publish should show in menus. This will break back-compatibility for any sites using custom public post statuses that are publicly viewable.

As noted on the PR, at a minimum it should check for is_post_status_viewable() and consider any post status that is valid.

The ticket description also mentions the "need to properly handle private posts too". I agree that would be helpful to work out.

On a site making use of the private post status and placing the items in the menu, my expectation is that the menu item would be shown to users who can access it and not to users who can not.

It would be helpful to get some testing notes on that use case for what happens now and with the patch applied.

#58 @oglekler
3 months ago

  • Keywords needs-testing removed

Thank you @peterwilsoncc, I was thinking about other statuses that are equal to publish but just didn't come across them. Let's wait for updated patch.

#59 @kush123
3 months ago

Hello @peterwilsoncc, thank you for the review. I have added a new condition to check if the current user has access to a private post. If YES, then the menu item will be visible. I have also included the test conditions in the description.

Note: See TracTickets for help on using tickets.