Make WordPress Core

Opened 10 years ago

Closed 4 months ago

#39558 closed enhancement (wontfix)

A lot of menu classes (and id's) are missing when there's no menu set for a location

Reported by: benoitchantre Owned by:
Priority: normal Milestone: Awaiting Review
Component: Menus Version: 4.7
Severity: normal Keywords:
Cc: Focuses: template

Description

When a fallback menu is displayed because no menu is set to a location, a lot of the CSS classes are removed, compared to the same menu when the location is set.

Would it be possible for a fallback menu to have the same classes than a menu with a location?
It would allow theme developers to use classes instead of tags to style the menu.

Fallback menu

<div id="primary-menu" class="menu">
	<ul>
		<li class="page_item page-item-3"><a href="test.dev/accueil/">Accueil</a></li>
		<li class="page_item page-item-703"><a href="test.dev/blog/">Blog</a></li>
		<li class="page_item page-item-4"><a href="test.dev/contact/">Contact</a></li>
		<li class="page_item page-item-701 current_page_item"><a href="test.dev/">Front Page</a></li>
		<li class="page_item page-item-2 page_item_has_children"><a href="test.dev/about/">About The Tests</a>
			<ul class="children">
				<li class="page_item page-item-1133"><a href="test.dev/about/page-image-alignment/">Page Image Alignment</a></li>
				<li class="page_item page-item-1134"><a href="test.dev/about/page-markup-and-formatting/">Page Markup And Formatting</a></li>
				<li class="page_item page-item-501"><a href="test.dev/about/clearing-floats/">Clearing Floats</a></li>
				<li class="page_item page-item-155"><a href="test.dev/about/page-with-comments/">Page with comments</a></li>
				<li class="page_item page-item-156"><a href="test.dev/about/page-with-comments-disabled/">Page with comments disabled</a></li>
			</ul>
		</li>
		<li class="page_item page-item-174 page_item_has_children"><a href="test.dev/level-1/">Level 1</a>
			<ul class="children">
				<li class="page_item page-item-173 page_item_has_children"><a href="test.dev/level-1/level-2/">Level 2</a></li>
				<li class="page_item page-item-742"><a href="test.dev/level-1/level-2a/">Level 2a</a></li>
				<li class="page_item page-item-744"><a href="test.dev/level-1/level-2b/">Level 2b</a></li>
			</ul>
		</li>
		<li class="page_item page-item-146"><a href="test.dev/lorem-ipsum/">Lorem Ipsum</a></li>
		<li class="page_item page-item-733"><a href="test.dev/page-a/">Page A</a></li>
		<li class="page_item page-item-735"><a href="test.dev/page-b/">Page B</a></li>
	</ul>
</div>

Menu with a location

<div class="menu-container">
	<ul id="primary-menu" class="menu">
		<li id="menu-item-1708" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item page-item-701 current_page_item menu-item-1708"><a href="test.dev/">Front Page</a></li>
		<li id="menu-item-1705" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1705"><a href="test.dev/level-1/">Level 1</a></li>
		<li id="menu-item-1706" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-1706"><a href="test.dev/level-1/level-2/">Level 2</a>
		<ul class="sub-menu">
			<li id="menu-item-1709" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1709"><a href="test.dev/level-1/level-2a/">Level 2a</a></li>
			<li id="menu-item-1710" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-1710"><a href="test.dev/level-1/level-2b/">Level 2b</a></li>
		</ul>
		</li>
		<li id="menu-item-1713" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1713"><a href="test.dev/contact/">Contact</a></li>
	</ul>
</div>

Change History (2)

#2 @terraGirl
4 months ago

  • Resolution → wontfix
  • Status new → closed

@SergeyBiryukov Edith here, working on Contributor Day at WCEU. This ticket interests me, as I've worked with the menu walkers but wasn't aware of this fallback quirk. Please let me know if you agree with closing this.

Behaviour summary

When wp_nav_menu() falls back to wp_page_menu() because no menu is assigned to a theme location, the rendered <li> items receive a different and smaller set of CSS classes than items in a properly assigned nav menu. Theme developers cannot use a single CSS selector to style both cases.

Fallback output:

class="page_item page-item-42 current_page_item"

Normal nav menu output:

class="menu-item menu-item-type-post_type menu-item-object-page menu-item-42 current-menu-item current_page_item"

Root cause

wp_nav_menu() in src/wp-includes/nav-menu-template.php#L167-L170 short-circuits immediately when no menu is found and calls the fallback:

if ( ( ! $menu || is_wp_error( $menu ) || ( isset( $menu_items ) && empty( $menu_items ) && ! $args->theme_location ) )
    && isset( $args->fallback_cb ) && $args->fallback_cb && is_callable( $args->fallback_cb ) ) {
        return call_user_func( $args->fallback_cb, (array) $args );
} 

This early return bypasses:

  • _wp_menu_item_classes_by_context() at line 201 — which sets menu-item, menu-item-type-*, menu-item-object-*, and all current-menu-* classes
  • Walker_Nav_Menu entirely

The default fallback_cb is wp_page_menu src/wp-includes/nav-menu-template.php#L74. That function calls wp_list_pages() which uses Walker_Page, producing the page_item / page-item-{ID} / current_page_* class family instead.

Class comparison:

Class Normal menu Fallback
menu-item ✓ ✗
menu-item-type-post_type ✓ ✗
menu-item-object-page ✓ ✗
menu-item-{ID} ✓ ✗
current-menu-item ✓ ✗
current-menu-ancestor ✓ ✗
current-menu-parent ✓ ✗
menu-item-has-children ✓ ✗
page_item ✓ (via compat) ✓
page-item-{ID} ✓ (via compat) ✓
current_page_item ✓ ✓
current_page_ancestor ✓ ✓
current_page_parent ✓ ✓

Scope

  • Affected: Classic themes using wp_nav_menu() with the default fallback_cb => 'wp_page_menu'. Covers TwentyTen through TwentyTwentyOne and any custom classic theme.
  • Not affected: FSE themes (TwentyTwentyTwo+, WordPress 5.9+). They use the Navigation block, which falls back to core/page-list — an independent rendering path that already outputs current-menu-item, current-menu-ancestor, and has-child using its own logic.
  • Confirmed reproducible in TwentyTwenty, TwentyFourteen and TwentyEleven with no menu assigned to the primary location.

Recommendation

Whilst the wish to have a uniform approach to menus is understandable, I recommend closing as "won't fix" as the impact on existing themes is signficant. A fix would change a standard approach in classic themes used for the past 16 years, resulting in CSS styles being applied to menus that never had them before. Good backwards compatibility is not possible.

I recommend to also close
https://core.trac.wordpress.org/ticket/18842

Note: See TracTickets for help on using tickets.