Make WordPress Core

Opened 5 years ago

Last modified 20 months ago

#22022 new defect (bug)

Can’t properly add pages of type edit.php?post_type=xxx as submenu items to arbitrary parent menus

Reported by: jjharr Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 3.0
Component: Posts, Post Types Keywords: needs-patch
Focuses: administration Cc:

Description (last modified by SergeyBiryukov)

The following code illustrates the problem.

add_menu_page('My Pages', 'My Pages', 'edit_posts', 'parentslug', array(class, func));
add_submenu_page('parentslug', 'Settings', 'Settings', 'edit_posts', 'mysettings', array(class, func));
add_submenu_page('parentslug', 'Custom Post Type', 'Custom Post Type', 'edit_posts', 'edit.php?post_type=xxx'); 

When you click on the first submenu item, the menu stays open, displaying the submenu items as it should. When you click on the item for the custom post type, the parent menu is closed and submenu pages are not displayed.

The root of the problem is how $parent_page is handled for pages of type edit.php?post_type=xxx. In get_admin_page_parent(), $parent_file is always set to $submenu[$parent], which may cause the submenu slug to be different from $parent_file. But in _wp_menu_output, if the submenu slug and parent slug are not equal, the 'wp-has-current-submenu wp-menu-open' classes do not get added which means the menu gets displayed as being closed.

Since there are no actions called between get_admin_parent_page() and the output of the menu, the only workaround I can see is some ugly JS that fixes up the classes.

It seems like the least intrusive fix would be to just move the call to apply_filters("parent_file) in menu-header.php to after the call to get_admin_page_parent() so that $parent_file can truly be overridden. This also seems inline with the intent of the filter.

Change History (8)

#1 @jjharr
4 years ago

  • Cc jjharr added

Providing a simpler explanation and a patch in hopes that something happens with this issue :

Simpler explanation : in menu-header.php, the 'parent_file' filter, which allows the user to set $parent_file, runs before the get_admin_page_parent() function. But the get_admin_page_parent() function can change $parent_file, overriding the filter value and rendering it ineffective. So the filter needs to run after that function.

Patch : All this does is swap the filter and function lines. The only way this would break existing code is if someone was relying on the internal behavior of get_admin_page_parent() to override the value they set in their filter function - which is not very likely.


--- wp-admin/menu-header.php
+++ wp-admin/menu-header.php
@@ -19,10 +19,11 @@ $self = preg_replace('|^.*/plugins/|i', '', $self);
 $self = preg_replace('|^.*/mu-plugins/|i', '', $self);

 global $menu, $submenu, $parent_file; //For when admin-header is included from within a function.
-$parent_file = apply_filters("parent_file", $parent_file); // For plugins to move submenu tabs around.


+$parent_file = apply_filters("parent_file", $parent_file); // For plugins to move submenu tabs around.
  * Display menu.


Last edited 4 years ago by jjharr (previous) (diff)

#2 @SergeyBiryukov
4 years ago

  • Component changed from Menus to Administration

#3 @SergeyBiryukov
4 years ago

  • Description modified (diff)

#4 @SergeyBiryukov
4 years ago

  • Keywords reporter-feedback added

Could not reproduce with the following code:

function codex_custom_init() {
    $args = array( 'public' => true, 'label' => 'Books', 'show_in_menu' => false );
    register_post_type( 'book', $args );
add_action( 'init', 'codex_custom_init' );

function dummy_page() {
	echo 'test';

function test_22022() {
	add_menu_page('My Pages', 'My Pages', 'edit_posts', 'parentslug', 'dummy_page');
	add_submenu_page('parentslug', 'Settings', 'Settings', 'edit_posts', 'mysettings', 'dummy_page');
	add_submenu_page('parentslug', 'Custom Post Type', 'Custom Post Type', 'edit_posts', 'edit.php?post_type=book'); 
add_action( 'admin_menu', 'test_22022' );

$parent_file and the submenu slug are the same (parentslug), so the 'wp-has-current-submenu wp-menu-open' classes are properly applied.

Am I missing something?

Last edited 4 years ago by SergeyBiryukov (previous) (diff)

#5 @SergeyBiryukov
4 years ago

  • Version changed from 3.4.2 to 3.0

parent_file filter was added in [12712].

#6 follow-up: @wycks
4 years ago

This happens when the parent and submenu page both exist, for example if you alter @SergeyBiryukov's example code above to 'show_in_menu' => true

The usage of duplicate menu items seems pretty edge case, maybe this should be address with mp6?

#7 in reply to: ↑ 6 @nacin
4 years ago

Replying to wycks:

The usage of duplicate menu items seems pretty edge case, maybe this should be address with mp6?

This isn't really in the purview of MP6.

#8 @chriscct7
20 months ago

  • Component changed from Administration to Posts, Post Types
  • Focuses administration added
  • Keywords needs-patch added; reporter-feedback removed

The usage of duplicate menu items seems pretty edge case

I actually ran into this making a plugin. It's something that would be trivial to fix in core.

Note: See TracTickets for help on using tickets.