Disable posts, only allow to edit existing pages, not create new ones (create_posts)

I am trying to limit a user role to only be able to edit existing pages, but not create new ones or do anything else like anything with posts.

I have read this:

Is there an existing capability to allow editing of only pre-existing pages? If not, a good way to implement this?
and the ticket mentioned there: https://core.trac.wordpress.org/ticket/16714

So I created a new user role with those permissions:

  • edit_pages
  • edit_others_pages
  • edit_published_pages
  • read

Then I added this:

function disable_page_creation(){    
  if( check_user_role('rolename'){ // This checks if the current user belongs to this role
     get_post_type_object('page')->cap->create_posts="do_not_allow";
  }
}

The problem is that this not only disables creation of new pages but also makes anything else like listing pages forbidden.

As soon as I just add edit_posts everything is working as expected in the pages section, but of course posts are editable now.

Is this something WP just isn’t capable of in this particular combination or am I just doing it wrong? Any hints where it gets stuck?


EDIT: Okay I think I am tracing down the issue. I believe the reason this happens is that posts and pages share the same admin file edit.php. Some more details:

The global $pagenow variable is set to edit.php no matter if we edit a post or a page.

In user_can_access_admin_page() this check is performed

 if ( isset( $_wp_menu_nopriv[$pagenow] ) ){

As the disabled post-editing puts edit.phpin $_wp_menu_nopriv[$pagenow] it also bails out for pages.

I’d say this is a WP bug. Can anyone confirm or does have a solution?

1
1

Okay here we go. It is a bug in WordPress itself.

I have already shortly explained the issue in my question, so either have a look at it or check out the ticket linked above for more details.

Until the issue is properly resolved I propose this dirty, dirty hack. It is based off the idea that as soon as another sub-menu that is accessible is added everything is working fine again. So we temporarily add a dummy submenu-item just to trick the check and then remove it immediately.

function workaround_issue_22895(){    
        add_submenu_page( 'edit.php?post_type=page', 'Workaround_Issue_22895', 'Workaround_Issue_22895', 'edit_pages', 'workaround_issue_22895' );
        add_filter('add_menu_classes', 'workaround_issue_22895_unset');    
}

add_action( 'admin_menu' , 'workaround_issue_22895' );

function workaround_issue_22895_unset ($menu){
    remove_submenu_page( 'edit.php?post_type=page', 'workaround_issue_22895');
    return $menu;
}

BTW, have I mentioned this is a dirty, dirty hack you should handle with care?

Leave a Comment