I am running a WordPress 5.2.3 site and having trouble with something in the admin panel.
I have a custom role, let's call it librarian
, and a custom post type, let's call it book
.
I want to make it so that a librarian
can edit a book
but not create a new one.
Following the advice in another question (WordPress: Disable “Add New” on Custom Post Type) and WordPress documentation, I have ended up with this code:
// Custom post type.
register_post_type('book',
array(
'labels' => array(
'name' => __( 'book' ),
'singular_name' => __( 'Book' )
),
'capability_type' => array('book', 'books'),
'capabilities' => array(
'create_posts' => 'do_not_allow' // <-- The important bit.
),
'map_meta_cap' => true,
'description' => 'Book full of pages',
'exclude_from_search' => true,
'publicly_queryable' => false,
'show_in_nav_menus' => false,
'show_ui' => true,
'show_in_menu' => true,
'show_in_rest' => true,
'menu_icon' => 'dashicons-location',
'menu_position' => 5,
'supports' => array('title', 'revisions')
));
// Custom role.
add_role('librarian', 'Librarian', array(
'read' => true,
'edit_books' => true,
'edit_published_books' => true
));
I was expecting that when I visited edit.php?post_type=book
as a librariran
then I would see the list of books
for editing, but I would not see the Add New button. However, what I actually get is a 403
response:
Sorry, you are not allowed to access this page.
I think this may be a bug in WordPress, because of the following cases:
edit.php?post_type=book
as an administrator
, then I see the list page without the Add New button, as desired.librarian
role the edit_posts
capability, then I see the list page without the Add New button, as desired (but I don't want to give them the edit_posts
capability!).These make me think that it isn't a problem with the custom post type set up in general.
'create_posts' => 'do_not_allow'
from the book
type registration, the librarian
can see the list page, but it includes the Add New button.This makes me think that it isn't a problem with the custom role set up in general.
Has anyone encountered this issue before? Have I missed anything from my configuration? Or is there an easy patch or workaround?
Any help would be appreciated! Thanks.
It appears that this is a bug in WordPress. I have found the source of the problem and a workaround.
If you're not interested in the cause, the workaround is to comment out this bit of cosmetic code in wp-admin/includes/menu.php
:
https://github.com/WordPress/WordPress/blob/master/wp-admin/includes/menu.php#L168
/*
* If there is only one submenu and it is has same destination as the parent,
* remove the submenu.
*/
if ( ! empty( $submenu[ $data[2] ] ) && 1 == count( $submenu[ $data[2] ] ) ) {
$subs = $submenu[ $data[2] ];
$first_sub = reset( $subs );
if ( $data[2] == $first_sub[2] ) {
unset( $submenu[ $data[2] ] );
}
}
This will mean that some menu items that previously didn't show a submenu now will (with a single item the same as the main menu item), but that is only a cosmetic UI change.
For those of you that want to know the detail…
Accessing edit.php?post_type=book
was failing this check in wp-admin/includes/menu.php
:
https://github.com/WordPress/WordPress/blob/master/wp-admin/includes/menu.php#L341
if ( ! user_can_access_admin_page() ) {
/**
* Fires when access to an admin page is denied.
*
* @since 2.5.0
*/
do_action( 'admin_page_access_denied' );
wp_die( __( 'Sorry, you are not allowed to access this page.' ), 403 );
}
The call to user_can_access_admin_page()
calls through to get_admin_page_parent()
.
If the submenu has been removed, get_admin_page_parent()
returns an empty parent which ultimately causes user_can_access_admin_page()
to erroneously return false
in the case of the librarian
role (the administrator
role passes for a different reason).
If the submenu is left in place, get_admin_page_parent()
returns a non-empty parent and the access check proceeds correctly from there.
So the root issue is that the global $submenu
is being used to both determine the UI and also to make decisions on the permissions hierarchy. I don't see an immediate quick fix for this problem that wouldn't have side effects elsewhere throughout the WordPress code, other than the workaround above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With