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.