Make WordPress Core

Opened 7 months ago

Last modified 3 weeks ago

#63261 assigned defect (bug)

Menu items incorrectly marked as current when page and taxonomy share the same object_id

Reported by: nuadagency's profile nuadagency Owned by: audrasjb's profile audrasjb
Milestone: Future Release Priority: normal
Severity: normal Version: 6.7.2
Component: Menus Keywords: has-patch reporter-feedback needs-test-info
Focuses: accessibility Cc:

Description (last modified by sabernhardt)

Description

If a page and a taxonomy term (e.g., product_cat) share the same numeric ID, both can be incorrectly marked as active in menus (current-menu-item, aria-current="page").

This occurs because WordPress checks only the object_id when determining the active menu item, without verifying that the object types match.

Steps to Reproduce

Create a WordPress page (e.g., "About") — assume it has ID 23.

Create a WooCommerce product category that also ends up with term_id = 23.

Add both items to a navigation menu.

Visit the product category archive (/product-category/boots/).

Observe that both menu items ("About" and "Boots") are marked as current.

Expected Result

Only the menu item representing the current object type (e.g., the product category) should be marked as current.

Actual Result

Both items are incorrectly highlighted due to ID match, even though they represent different object types.

Cause

In wp-includes/nav-menu-template.php, this comparison is made:

if ( $menu_item->object_id === $queried_object_id ) { $menu_item->current = true; }

This does not check if the object type (e.g. page, product_cat) also matches.

Proposed Fix

Enhance the condition to ensure both ID and object type match:

$queried_object_type = '';
if ( isset( $queried_object->post_type ) ) {
    $queried_object_type = $queried_object->post_type;
} elseif ( isset( $queried_object->taxonomy ) ) {
    $queried_object_type = $queried_object->taxonomy;
}
if ( (int) $menu_item->object_id === (int) $queried_object_id
    && $menu_item->object === $queried_object_type ) {
    $menu_item->current = true;
}

Environment

WordPress 6.7.2

WooCommerce 9.7.1

PHP 8.2

Notes

This issue causes confusing menu behavior and accessibility inconsistencies. It's especially common with WooCommerce where term IDs frequently overlap with page IDs.

Attachments (1)

63261.patch (1.2 KB) - added by abcd95 7 months ago.
There might be a better approach but this also works.

Download all attachments as: .zip

Change History (18)

#1 @sabernhardt
7 months ago

  • Description modified (diff)
  • Focuses coding-standards removed

#2 @audrasjb
7 months ago

  • Keywords needs-patch added
  • Milestone changed from Awaiting Review to 6.9
  • Owner set to audrasjb
  • Severity changed from minor to normal
  • Status changed from new to assigned

Hello and welcome to WordPress Core Trac!

I reproduced the issue on my side. Self assigning and moving to milestone 6.9.

@abcd95
7 months ago

There might be a better approach but this also works.

#3 @abcd95
7 months ago

  • Keywords needs-testing added; needs-patch removed

This ticket was mentioned in Slack in #accessibility by joedolson. View the logs.


6 months ago

#5 follow-up: @SirLouen
6 months ago

  • Keywords reporter-feedback has-patch added; needs-testing removed

Reproduction Report

Description

❌ This report can't validate that the issue can be reproduced.

Environment

  • WordPress: 6.9-alpha-60093-src
  • PHP: 8.2.28
  • Server: nginx/1.27.5
  • Database: mysqli (Server: 8.4.5 / Client: mysqlnd 8.2.28)
  • Browser: Chrome 136.0.0.0
  • OS: Windows 10/11
  • Theme: Twenty Twenty 2.9
  • MU Plugins: None activated
  • Plugins:
    • Test Reports 1.2.0

Reproduction Steps

  1. I create a page and check the ID. In this case id=6
  2. I create several Categories, until I get one with cat_id=6
  3. I add both elements to a Menu
  4. ❌ Going into each element doesn't cause both elements having current-menu-item, aria-current="page" as commented in the OP
  • Check the screencast for more info

Actual Results

  1. ❌ Error condition is not occurring.

Additional Notes

It appears that some people have been able to reproduce this. I'm not using WooCommerce because it's out of scope.
So I believe that simply using a post_type='post' and a regular category should have triggered the same error.
@nuadagency can you check my screencast + instructions and suggest how I can better reproduce this?

Supplemental Artifacts

Screencast: https://streamable.com/7mx8jf

Version 0, edited 6 months ago by SirLouen (next)

#6 in reply to: ↑ 5 @nuadagency
6 months ago

  • Keywords 2nd-opinion added; reporter-feedback removed

Thanks for reviewing this. I checked your screencast and test steps, and I think there’s a fundamental mismatch in what you attempted versus the issue I reported.

The original report is explicitly about conflicting object types — for example, a WP_Post (like a Page) and a WP_Term (like a product_cat taxonomy term) — sharing the same ID and being incorrectly marked as current in menus due to a loose object_id match.

Your test uses a Post and a Category — which are designed to work together in core — and both fall under WordPress's built-in post-category system. That setup doesn’t replicate the issue because it doesn’t create a type mismatch between objects.

So to reproduce this accurately, it’s necessary to involve a custom taxonomy like WooCommerce's product_cat. The issue typically occurs on term archive pages (e.g., /product-category/boots/) where a taxonomy term and a page share the same numeric ID, and both are added to the nav menu.

#7 @SirLouen
6 months ago

  • Keywords has-test-info needs-testing added; 2nd-opinion removed

I got your new testing instructions. I will reproduce it later and report.

#8 @SirLouen
6 months ago

  • Keywords reporter-feedback needs-test-info added; has-test-info needs-testing removed

2nd Reproduction Report

Description

❌ This report can't still validate that the issue can be reproduced with the latest instructions

Environment

  • WordPress: 6.9-alpha-60093-src
  • PHP: 8.2.28
  • Server: nginx/1.27.5
  • Database: mysqli (Server: 8.4.5 / Client: mysqlnd 8.2.28)
  • Browser: Chrome 136.0.0.0
  • OS: Windows 10/11
  • Theme: Twenty Twenty 2.9
  • MU Plugins: None activated
  • Plugins:
    • Test Reports 1.2.0

Reproduction Steps

  1. Given that we require to have a CPT like WooCommerce products and a custom taxonomy like product categories I've created both a Testing Example CPT and a Testing Taxonomy, code below
  2. I have also created a little shortcode to show current Taxonomy ID because the Slug wont show it easily for testing demonstration.
  3. Create a Post with certain ID, in my example 15
  4. Create a Example Testing Taxonomy inside Example Custom Post Type, with same ID as Post, in my example 15
  5. Create an Example Custom Post, and add the shortcode [current_taxonomy_id] to showcase the Taxonomy ID
  6. ❌ Going into each element doesn't cause both elements having current-menu-item, aria-current="page" as commented in the OP
  • Check the screencast for more info

Actual Results

  1. ❌ Error condition is not occurring.

Additional Notes

  • According to the reporter, @nuadagency, it was important to have a custom taxonomy to test this. Check code below in Supplemental Artifacts.
  • Waiting for a review of my testing protocol and in case something is wrong, new testing instructions because I have not been able to reproduce this for now.

Supplemental Artifacts

  1. Attaching a new screencast: https://f003.backblazeb2.com/file/wordpress-videos/wp-videos/2025/05/63261.2.mp4
  2. Test code
function register_testing_taxonomy() {
	$labels = array(
		'name'              => _x( 'Testings', 'general name' ),
		'singular_name'     => _x( 'Testing', 'singular name' ),
		'search_items'      => __( 'Search Testings' ),
		'all_items'         => __( 'All Testings' ),
		'parent_item'       => __( 'Parent Testing' ),
		'parent_item_colon' => __( 'Parent Testing:' ),
		'edit_item'         => __( 'Edit Testing' ),
		'update_item'       => __( 'Update Testing' ),
		'add_new_item'      => __( 'Add New Testing' ),
		'new_item_name'     => __( 'New Testing Name' ),
		'menu_name'         => __( 'Testing' ),
	);

	$args = array(
		'hierarchical'      => true,
		'labels'            => $labels,
		'show_ui'           => true,
		'show_admin_column' => true,
		'show_in_nav_menus' => true
		'query_var'         => true,
		'rewrite'           => array( 'slug' => 'testing' ),
	);

	register_taxonomy( 'testing', array( 'example_post' ), $args );
}
add_action( 'init', 'register_testing_taxonomy' );

function register_example_cpt() {
	$labels = array(
		'name'                  => __( 'Example Posts' ),
		'singular_name'         => __( 'Example Post' ),
		'menu_name'             => __( 'Example Posts' ),
		'name_admin_bar'        => __( 'Example Post' ),
		'add_new'               => __( 'Add New' ),
		'add_new_item'          => __( 'Add New Example Post' ),
		'new_item'              => __( 'New Example Post' ),
		'edit_item'             => __( 'Edit Example Post' ),
		'view_item'             => __( 'View Example Post' ),
		'all_items'             => __( 'All Example Posts' ),
		'search_items'          => __( 'Search Example Posts' ),
		'parent_item_colon'     => __( 'Parent Example Posts:' ),
		'not_found'             => __( 'No example posts found.' ),
		'not_found_in_trash'    => __( 'No example posts found in Trash.' ),
	);

	$args = array(
		'labels'             => $labels,
		'public'             => true,
		'publicly_queryable' => true,
		'show_ui'            => true,
		'show_in_menu'       => true,
		'query_var'          => true,
		'rewrite'            => array( 'slug' => 'example_post' ),
		'capability_type'    => 'post',
		'has_archive'        => true,
		'hierarchical'       => false,
		'menu_position'      => null,
		'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
		'taxonomies'         => array( 'testing' ),
	);

	register_post_type( 'example_post', $args );
}
add_action( 'init', 'register_example_cpt' );

function show_current_taxonomy_id_shortcode() {
	$term = get_queried_object();
	if ( $term && isset( $term->taxonomy ) && isset( $term->term_id ) ) {
		return esc_html( $term->term_id );
	} else {
		return 'Not a taxonomy page';
	}
}
add_shortcode( 'current_taxonomy_id', 'show_current_taxonomy_id_shortcode' );
Last edited 6 months ago by SirLouen (previous) (diff)

#9 follow-up: @nuadagency
6 months ago

Hi @SirLouen , thank you again for putting time into this — I really appreciate the effort and detailed feedback.

I think the core of the issue might be a misunderstanding of the condition required to trigger this bug. Let me try to rephrase and clarify.

What specifically triggers this
The bug occurs only when:

A WordPress Page (a WP_Post with post_type = page) and a taxonomy term (like a WooCommerce product_cat) share the same numeric ID.

Both the Page and the Term are added to a navigation menu.

The user visits a term archive page (e.g., /product-category/boots/).

On that archive page, WordPress sees the term ID (e.g., 23) and flags both menu items with object_id = 23 as current, without checking whether they're the same type (post vs term).

Why your reproduction isn’t working
In your test, you're using a custom post type and a taxonomy attached to that same CPT. That relationship is expected in WordPress and doesn't replicate the bug.

You're not creating the required mismatch of unrelated object types.

How to reproduce it accurately
Create a normal Page in WordPress — e.g., "About" with ID 23.

Create a WooCommerce Product Category that happens to get term_id = 23.

Add both the Page and Product Category to a nav menu.

Visit the Product Category archive (/product-category/example/).

Observe that both menu items get marked current-menu-item even though only the term is active.

Let me know if that clears things up. It's a subtle bug, but easily reproducible in default/fresh WooCommerce installs.

#10 in reply to: ↑ 9 @SirLouen
6 months ago

Replying to nuadagency:

Why your reproduction isn’t working
In your test, you're using a custom post type and a taxonomy attached to that same CPT. That relationship is expected in WordPress and doesn't replicate the bug.

You're not creating the required mismatch of unrelated object types.

This is not correct

In my last reproduction "Test Tax" was a post_type=post and the "b" was a Taxonomy of type testing.

I only created a CPT because I wanted to simplify the demonstration that both ID (for post and for taxonomy testing) were the same (15) without leaving the screen.

According to your mismatch theory in my example, post, and taxonomy testing are completely unrelated.

I've also tried with post_type=page and my taxonomy testing with the same ID and still not finding this problem.

I'm not using your exact WooCommerce example for testing because this is just one use-case that served me as an example of what I should be testing, but to do a real testing, it has to prove to be generalizable under equivalent conditions. Because maybe the problem is only related with WooCommerce product_cat (unlikely but possible)

I've provided the code I'm using, so if you like, you can dig a bit with it and compare.

Last edited 6 months ago by SirLouen (previous) (diff)

#11 @nuadagency
6 months ago

Thanks @SirLouen — I went through your test setup step by step and can confirm that, under those conditions (WP 6.8.1, custom taxonomy with the same ID as a page), the issue does not occur. So your reproduction path is valid in proving that not all object ID collisions cause the bug.

However, I want to clarify that in the original reported instance (also updated to 6.8.1 now), the issue still persists — specifically:

A page and a product_cat term share the same ID

Both are in the navigation menu

Visiting the product category archive (e.g., /product-category/kat/) still results in both items being marked as current-menu-item, which is incorrect

@audrasjb — since you mentioned earlier that you were able to reproduce this, could you possibly share:

The exact environment/setup used for reproduction?

Any specific conditions (menu structure, object types, filters/hooks) that triggered the bug on your end?

This could help pinpoint why it still appears in some WooCommerce installs, but not others — even on the same WP version — and clarify whether the root cause is in core or indirectly introduced via plugin/theme behavior.

Thanks in advance!

#12 @SirLouen
6 months ago

@nuadagency can you check in the WooCommerce code to see if there are references to the given HTML devices like current-menu-item and aria-current? Maybe there is some code duplicating this behaviour.

This ticket was mentioned in Slack in #accessibility by joedolson. View the logs.


6 weeks ago

#14 @joedolson
6 weeks ago

@nuadagency Have you been able to determine whether this is an issue specific to WooCommerce? Right now, with no ability to reproduce the issue with no plugins, it's hard to determine that this is definitely a core issue.

This ticket was mentioned in Slack in #accessibility by mdrhmaruf. View the logs.


4 weeks ago

This ticket was mentioned in Slack in #accessibility by joedolson. View the logs.


3 weeks ago

#17 @joedolson
3 weeks ago

  • Milestone changed from 6.9 to Future Release

With it being unclear whether we can reproduce this, and already being in beta, I'm going to move this to future release. We can explore it further after 6.9!

Note: See TracTickets for help on using tickets.