Hiding Admin Page While Keeping Menu Expanded
-
29-01-2021 - |
题
I am creating a custom admin section. I have the following code:
// Top level menu
add_menu_page('Books', 'Books', 'publish_posts', 'books', 'render_books_page', '', 17);
// Adding this function to make the first submenu have a different name than the main menu
// Details: https://wordpress.stackexchange.com/questions/66498/add-menu-page-with-different-name-for-first-submenu-item
add_submenu_page('Books', 'Books', 'All Books', 'publish_posts', 'books', 'render_books_page');
// The Add Book menu page
add_submenu_page('Books', 'Add New Book', 'Add Book', 'publish_posts', 'add-book', 'render_add_book_page');
// The Edit Book menu page (this page is hidden from the menu, and accessed via the All Books page only)
add_submenu_page(null, 'Edit Book', 'Edit Book', 'publish_posts', 'edit-book', 'render_edit_book_page');
As you notice in the last line of code, the first parameter of the add_submenu_page()
is set to null
. This is to ensure that the Edit Book page is hidden (more details about this here). Access to the Edit Book page is done via the main menu, from the list of all books.
The problem is, when I go to the Edit Book page, the Admin Menu to the left collapses (on the other hand, the default WordPress behaviour is as follows: If you go to an Edit Post page, or the Edit Page page, both the Posts and Pages menu stay expanded for their respective edit pages). In my case, the menu collapses.
How can I keep the menu to the left expanded when I go to the Edit Book page, to behave in a similar fashion to that of WordPress?
Thanks.
解决方案 2
The solution is based on the ideas provided by @Ian. Thanks.
add_action( 'admin_menu', 'add_the_menus' );
function add_the_menus() {
// Top level menu
add_menu_page ('Books', 'Books', 'publish_posts', 'books', 'render_books_page', '', 17);
// Adding this function to make the first submenu have a different name than the main menu
add_submenu_page('books', 'Books', 'All Books', 'publish_posts', 'books', 'render_books_page' );
if ((isset($_GET['page'])) && ($_GET['page'] === 'edit-book')) {
// The Edit Book menu page and display it as the All Books page
add_submenu_page('books', 'Edit Book', 'All Books', 'publish_posts', 'edit-book', 'render_edit_book_page' );
}
// The add-book menu page
add_submenu_page('books', 'Add New Book', 'Add New', 'publish_posts', 'add-book', 'render_add_book_page' );
}
And we must hide the first menu item
add_action( 'admin_enqueue_scripts', function () {
if ((isset($_GET['page'])) && ($_GET['page'] === 'edit-book')) {
// Load CSS file
wp_enqueue_style('book-edit', 'path/to/css/menu.css');
// Load jQuery
wp_enqueue_script('jquery');
// Load
wp_enqueue_script('book-edit-script', 'path/to/js/menu.js');
}
});
And the content of menu.css
is:
#toplevel_page_books li.current {
display: none;
}
#toplevel_page_books li.wp-first-item {
display: list-item;
}
Also the content of 'menu.js' is:
jQuery(document).ready(function($) {
$('#toplevel_page_books li.wp-first-item').addClass('current');
});
TL;DR
To understand how all this works, here is a step-by-step explanation.
Step 1: We add the main menu item (the books menu item) to display the list of books
add_action( 'admin_menu', 'add_the_menus' );
function add_the_menus() {
// Top level menu
add_menu_page ('Books', 'Books', 'publish_posts', 'books', 'render_books_page', '', 17);
}
Step 2: We add the add-book menu item as a submenu to the main books menu item
add_action( 'admin_menu', 'add_the_menus' );
function add_the_menus() {
// Top level menu
add_menu_page ('Books', 'Books', 'publish_posts', 'books', 'render_books_page', '', 17);
// The add-book menu page
add_submenu_page('books', 'Add New Book', 'Add New', 'publish_posts', 'add-book', 'render_add_book_page' );
}
Step 3: Finishing Step 2 above adds the books menu item, The menu list on the left side would look like this:
Books <---------- This is the main top level menu names
Books <---------- This is the first sub-menu
Add New <---------- This is the second sub-menu
However, we should fix this. The intended list should look like this
Books <---------- This is the main top level menu names
All Books <---------- This is the first sub-menu
Add New <---------- This is the second sub-menu
To do this, we have to modify our code as follows:
add_action( 'admin_menu', 'add_the_menus' );
function add_the_menus() {
// Top level menu
add_menu_page ('Books', 'Books', 'publish_posts', 'books', 'render_books_page', '', 17);
// Adding this function to make the first submenu have a different name than the main menu
add_submenu_page('books', 'Books', 'All Books', 'publish_posts', 'books', 'render_books_page' );
// The add-book menu page
add_submenu_page('books', 'Add New Book', 'Add New', 'publish_posts', 'add-book', 'render_add_book_page' );
}
Step 4: Next we should add a sub menu to edit books (the edit-book menu item). After adding his submenu, and when we are at the edit-book page, the menu on the left should look like this:
Books
All Books <---------- When we are in the 'edit-book' page, this menu item is selected and is highlighted (typically white in color), and also clicking on "All Books" would return us back to the "All Books" page.
Add New
The solution I tried first was what I posted in my original question, which did not work exactly. So, based on discussions with @Ian and looking at his proposed solution, I came up with this:
add_action( 'admin_menu', 'add_the_menus' );
function add_the_menus() {
// Top level menu
add_menu_page ('Books', 'Books', 'publish_posts', 'books', 'render_books_page', '', 17);
// Adding this function to make the first submenu have a different name than the main menu
add_submenu_page('books', 'Books', 'All Books', 'publish_posts', 'books', 'render_books_page' );
// If we are in the 'edit-book' page, then display the 'edit-book' submenu, otherwise, display the regular 'books' menu
if ((isset($_GET['page'])) && ($_GET['page'] === 'edit-book')) {
// Display the 'edit-book' menu page and display it as the 'all-books' page
// Notice that the slug is 'edit-book', but the display name is 'All Books'
add_submenu_page('books', 'Edit Book', 'All Books', 'publish_posts', 'edit-book', 'render_edit_book_page' );
}
// The add-book menu page
add_submenu_page('books', 'Add New Book', 'Add New', 'publish_posts', 'add-book', 'render_add_book_page' );
}
Now, if we click on the 'books' menu item, or the 'add-book' menu item, then everything is fine. However, if we try to edit an existing book then the following menu list will be displayed
Books
All Books <---------- This is the first sub-menu (due to the first submenu call)
All Books <---------- This is the 'edit-book' page (HIGHLIGHTED)
Add New
Step 5: Now we notice the following: By clicking on the first submenu, the "All Books" page will be rendered, and clicking on the second submenu will render the "Edit" page; and in our case, we want to render the "All Books" page. Therefore, we have to hide the SECOND submenu and make the first submenu highlighted. This is done as follows:
add_action( 'admin_enqueue_scripts', function () {
if ((isset($_GET['page'])) && ($_GET['page'] === 'edit-book')) {
// Load CSS file
wp_enqueue_style('book-edit', 'path/to/css/menu.css');
// Load jQuery
wp_enqueue_script('jquery');
// Load
wp_enqueue_script('book-edit-script', 'path/to/js/menu.js');
}
});
And the content of menu.css
is:
#toplevel_page_books li.current {
display: none;
}
#toplevel_page_books li.wp-first-item {
display: list-item;
}
Also the content of 'menu.js' is:
jQuery(document).ready(function($) {
$('#toplevel_page_books li.wp-first-item').addClass('current');
});
And now everything works like a charm.
其他提示
For your particular situation, where you need to have a menu registered, but not shown unless you click on it from a link on another page you can add a conditional check to see if you're on the editing page. If so, then change replace null
with book
per the add_submenu_page()
parameters.
add_action( 'admin_menu', 'add_the_menus' );
function add_the_menus() {
// Top level menu
add_menu_page( 'Books', 'Books', 'publish_posts', 'books', 'render_books_page', '', 17 );
// Adding this function to make the first submenu have a different name than the main menu
add_submenu_page( 'books', 'Books', 'All Books', 'publish_posts', 'books', 'render_books_page' );
// The Add Book menu page
add_submenu_page( 'books', 'Add New Book', 'Add Book', 'publish_posts', 'add-book', 'render_add_book_page' );
// Check the get parameter for page to see if its the page you want to display in the menu only when you're on it.
if ( $_GET['page'] === 'edit-book' ) {
// The Edit Book menu page (this page is hidden from the menu, and accessed via the All Books page only)
add_submenu_page( 'books', 'Edit Book', 'Edit Book', 'publish_posts', 'edit-book', 'render_edit_book_page' );
} else {
// The Edit Book menu page (this page is hidden from the menu, and accessed via the All Books page only)
add_submenu_page( null, 'Edit Book', 'Edit Book', 'publish_posts', 'edit-book', 'render_edit_book_page' );
}
}
An additional note. If it turns out that you need to also keep that menu item hidden even when selected you can enqueue a style to hide it only when you're on that page.
add_action( 'admin_enqueue_scripts', function () {
if ( $_GET['page'] === 'edit-book' ) {
wp_enqueue_style( 'book-edit', get_stylesheet_directory_uri() . '/assets/css/book-edit.css' );
}
} );
Where the contents of book-edit.css would be something as simple as:
#toplevel_page_books li.current {
display: none;
}