WordPress.org

Make WordPress Core

Opened 4 years ago

Closed 3 years ago

#14844 closed defect (bug) (invalid)

wp_nav_menu producing unexpected results

Reported by: holypixel Owned by:
Milestone: Priority: normal
Severity: normal Version: 3.0.1
Component: Menus Keywords: reporter-feedback close
Focuses: Cc:

Description

My question may be irrelevant, as I am somewhat new to wordpress and the wp_nav_menu system, however I am having a few issues with something...

If I add the same page (child) to multiple parents, wordpress will create a css class called current-menu-item, which is as expected, however it will add that class to all of the instances of that child. For example:

PARENT 1 --- PARENT 2 --- PARENT 3
ITEM A ----- ITEM B ----- ITEM C
ITEM D ----- ITEM D ----- ITEM F
ITEM G ----- ITEM H ----- ITEM I

Item D, under both parent 1 and parent 2 will have the css class current-menu-item. This appears to be incorrect, as they are both differnt menu items. It also lists current-page-item for both, which is correct.

As such, it appears impossible to apply unique styling to the current page parent if that page appears under multiple parents, as all of the parents will receive the same style.

Is there a way around this?

Change History (8)

comment:1 in reply to: ↑ description filosofo4 years ago

Replying to holypixel:

Item D, under both parent 1 and parent 2 will have the css class current-menu-item. This appears to be incorrect, as they are both differnt menu items. It also lists current-page-item for both, which is correct.

I don't understand why you think that is incorrect. If I am currently viewing the Item D page, then Item D is the current item, no matter what list it appears in. Item D is identical to Item D, so it's not as though one Item D appears in a different place in the actual site hierarchy than the other.

And from a practical matter, how is WordPress supposed to know which Item D you really intend to be visiting? Each Item D has the same URL, so there's no way to distinguish them.

Think about it this way. I might categorize the United States under multiple lists: say "North American Countries" or "UN Security Council Members," but for each list it is still correct to say that the United States is the country in which I currently reside.

As such, it appears impossible to apply unique styling to the current page parent if that page appears under multiple parents, as all of the parents will receive the same style.

Is there a way around this?

To me this seems like a conceptual problem, not a technical one. Instead of trying to make two identical objects differ, try making two different objects.

comment:2 filosofo4 years ago

  • Keywords reporter-feedback close added; wp_nav_menu current-menu-item removed

comment:3 follow-up: holypixel4 years ago

Yes you are right in the sense that Item D is identical, no matter what menu it is in, however to not be able to differentiate between instances from a semantic point of view is quite impractical, particularly when it comes to styling and creating child only side menus etc.

Conceptually, yes it is possible to create two versions of item D (for example) which are different, however surely that defeats the purpose of allowing a single page to have multiple instances in the menu system (clearly an intended function of wp_nav_menu). Trying to explain to clients why they have to duplicate pages simply to keep the site functioning correctly confuses matters (many want pricing to appear in multiple menus for example).

Technically, there is no reason why wordpress can't differentiate between children, or any menu item for that matter using the menu-item-id, as that is unique to every menu item. All that would be required is that when a menu item is selected by the user, wordpress creates a variable containing the selected menu-item-id to be used by the _wp_menu_item_classes_by_context function.

To be more specific, the _wp_menu_item_classes_by_context function in nav-menu-template currently works like so...

$menu_item->object_id == $queried_object_id &&

It would simply need to be changed to..

$menu_item->ID == $selected_menu_item_id &&

To me it just seems kind of pointless having a current-menu-item class that doesn't actually denote what it is supposed to denote...

Thanks for your help... I dont mean to sound too direct!

comment:4 in reply to: ↑ 3 filosofo4 years ago

Replying to holypixel:

Technically, there is no reason why wordpress can't differentiate between children, or any menu item for that matter using the menu-item-id, as that is unique to every menu item. All that would be required is that when a menu item is selected by the user, wordpress creates a variable containing the selected menu-item-id to be used by the _wp_menu_item_classes_by_context function.

I'm unsure what you mean by "selected by the user." Do you mean, request the page represented by that menu link? In other words, click one of the Item D menu links?

If so, then the problem is that the link clicked is the same no matter which instance of Item D in the menu you follow: Item D on your left links to http://example.com/item-d-page/, and Item D on your right links to the same, http://example.com/item-d-page/. How is WordPress supposed to know when you request http://example.com/item-d-page/ whether you mean Item D on the left or the right?

You mention children. WordPress does distinguish ancestry for different children. Say Item K is under right-hand Item D in the menu. Then when you request Item K's page, right-hand menu Item D gets the current-menu-ancestor class; left-hand menu Item D does not. In that case, it there is a reasonable way to distinguish which Item D menu item should be affected, and WP does so.

comment:5 follow-up: holypixel4 years ago

Yea thats correct, I mean when a user clicks one of the Item D menu links...

I realise that they all link to the item D page, however the links themselves are uniquely identified by the menu-item-id. It is using the menu-item-id as opposed to the target page or url that I propose using as the identifier.

For example, the menu link could contain the menu-item-id, so that when clicked wordpress could create the variable containing that ID, as I proposed in the previous message.

Your example of current-menu-ancestor is good in theory, however if that is the way it is supposed to work, then it is broken. In all of my tests multiple instance children under different parents will create the current-menu-ancestor class on the parents, just the same as the current-menu-item. I presume this is because current-menu-ancestor is determined by current-menu-item, and if current-menu-item doesn't differentiate, then would why ancestor?

Please see http://www.apersonaldogtrainer.com.au as my example. You will notice that 'pricing' appears under training, boarding, grooming and about me. If pricing is the current page, then training, boarding, grooming and about me all have the current-menu-ancestor class applied, in addition to current-menu-parent. That doesn't appear to mesh with your comments on how it is supposed to work.

It is either broken or I am seriously not understanding something. Throughout our discussion you have said that wordpress cannot differentiate between the menu items if they are multiple instances due to the fact that their target's are the same. If that is the case, then why even bother having the current-menu-item, current-menu-parent or current-menu-ancestor classes, if all they do is mirror the curren-page style of classes?

comment:6 holypixel4 years ago

... I just reread your comment on the current-menu-ancestor, and it now makes more sense, in that it differentiates between complete menus. I can now see the benefit and purpose of the current-menu classes.

Unfortunately this still doesn't resolve the issue that I am having (and a number of others from what I have read). Surely it is possible to integrate a function as I have proposed to help differentiate between multiple instance children in the same menu.

To allow multiple instances in the wp_nav_menu system, but not support them semantically seems pretty crippled.

comment:7 in reply to: ↑ 5 filosofo4 years ago

Replying to holypixel:

I realise that they all link to the item D page, however the links themselves are uniquely identified by the menu-item-id. It is using the menu-item-id as opposed to the target page or url that I propose using as the identifier.

HTTP is stateless. That means that no information is kept from one page request to the other. Say you're looking at page A, and you click a link with ID X that requests page B.

When you request page B the server doesn't know that you just clicked a link with ID X. It just knows about the resource you're requesting at that moment (page B) and some additional information usually transmitted in the HTTP headers, such as the referrer (page A) and cookies.

So to let the server know that you're requesting Item D by following the right-hand Item D menu item link, you basically have two options:

  • Change the Item D menu links so that they are different from each other, perhaps by adding arguments or fragments:
    • http://example.com/item-d-page/?from-clicking=id-item-123
    • http://example.com/item-d-page/#id-item-123
  • Capture the click event using JavaScript and set a cookie that saves the ID of the last link clicked.

Perhaps you can see that implementing these potential solutions systematically would be too convoluted and obscure for core WordPress; they are solutions best implemented by plugins.

It is either broken or I am seriously not understanding something. Throughout our discussion you have said that wordpress cannot differentiate between the menu items if they are multiple instances due to the fact that their target's are the same. If that is the case, then why even bother having the current-menu-item, current-menu-parent or current-menu-ancestor classes, if all they do is mirror the curren-page style of classes?

The classes reflect the state of the current page (remember that HTTP is stateless). They do not reflect your browsing history (such as the fact that you clicked a particular link to arrive at this current page). So when you are viewing the Item D page, the server that generated its markup does not care or know about the ID of the link you followed to view that page; it just knows that this is the Item D page so those Item D menu links need classes to indicate that they are the currently-generated page.

To allow multiple instances in the wp_nav_menu system, but not support them semantically seems pretty crippled.

All the other classes reflect the semantics of the menu structure and the menu items' relationships to the currently requested page. None reflects the client's browsing history, which is what you're asking for. In fact, it would be considered bad practice if the idempotent GET request method (what you use to load a page by following a link) resulted in markup that changed according to browsing history. In other words, good practice suggests that multiple, identical requests should get identical responses (in truth though WP breaks this a lot in the admin).

comment:8 nacin3 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Status changed from new to closed
Note: See TracTickets for help on using tickets.