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:
- If I visit
edit.php?post_type=book
as anadministrator
, then I see the list page without the Add New button, as desired. - If I give the
librarian
role theedit_posts
capability, then I see the list page without the Add New button, as desired (but I don't want to give them theedit_posts
capability!).
These make me think that it isn't a problem with the custom post type set up in general.
- If I remove the
'create_posts' => 'do_not_allow'
from thebook
type registration, thelibrarian
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.
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
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.
Cause
For those of you that want to know the detail…
Accessing
edit.php?post_type=book
was failing this check inwp-admin/includes/menu.php
:https://github.com/WordPress/WordPress/blob/master/wp-admin/includes/menu.php#L341
The call to
user_can_access_admin_page()
calls through toget_admin_page_parent()
.If the submenu has been removed,
get_admin_page_parent()
returns an empty parent which ultimately causesuser_can_access_admin_page()
to erroneously returnfalse
in the case of thelibrarian
role (theadministrator
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.