How do I code access to the built-in UI of a CPT when it’s placed as submenu of another CPT that is protected by role?


I am toying around with WordPress capabilities, and having some difficulty understanding where I am going wrong. Right now, I have an admin menu that appears for all administrators with STUDENTS as a submenu of SCHOOL: each of those link to http://example.com/wp-admin/edit.php?post_type=student. (When the user is in the HEADMASTER role, the link to the built-in UI for TEACHER appears and SCHOOL mimics its link). So far, all is well.

The bump in the road is when a non-HEADMASTER administrator clicks either SCHOOL or STUDENTS, the error “Sorry, you are not allowed to access this page” appears. (As expected, when that same admin accesses http://example.com/wp-admin/edit.php?post_type=teacher, the errors “You need a higher level of permission” and “Sorry, you are not allowed to edit posts in this post type” appear.) The issue is that the STUDENTS built-in UI is not accessible to all administrators. (As expected, there are no problems for HEADMASTERs.) How can this be resolved in such a way as to give all site admins access to STUDENTS and only HEADMASTERs access to TEACHERS while at the same time preserving the layout and functionality of the admin menu and built-in UI?

What I’ve Tried: When the 'show_in_menu' => 'edit.php?post_type=teacher' line is removed from the STUDENTS CPT, everything works as expected but STUDENTS becomes a top-level menu item instead of SCHOOL. I tried putting TEACHERS as a sub-menu item as STUDENTS, but SCHOOL does not change its link when the user is in the HEADMASTER role (also the ordering of TEACHERS and STUDENTS is backwards). I also tried add_menu_page() for SCHOOL and adding the slug returned for the show_in_menu argument of the TEACHERS and STUDENTS register_post_type args, respectively, but that didn’t work because it created a page instead of forwarding to the appropriate built-in UI.

 class School {     public static function init() {         add_action('init', array(__CLASS__, 'register_cpt'));         add_action('init', array(__CLASS__, 'add_role'));         add_action('admin_menu', array(__CLASS__, 'modify_menu'));     }      public static function register_cpt() {         register_post_type('teacher', array(             'labels' => array(                 'name'          => __('TEACHER'),                 'all_items'     => __('TEACHERS'),                 'menu_name'     => __('SCHOOL'),             ),             'show_ui'           => TRUE,             'capability_type'   => 'educator',             'map_meta_cap'      => TRUE,         ));         register_post_type('student', array(             'labels' => array(                 'name'          => __('STUDENT'),                 'menu_name'     => __('STUDENTS'),             ),             'show_ui'           => TRUE,             'show_in_menu'      => 'edit.php?post_type=teacher',         ));     }      public static function add_role() {         if(get_role('headmaster') === NULL) {             $  caps = array();             foreach(get_role('administrator')->capabilities as $  cap => $  tmp) {                 $  pos = strpos($  cap, 'post');                 if($  pos !== FALSE) {                     $  cap = str_replace('post', 'educator', $  cap);                     $  caps[$  cap] = TRUE;                 }             }             add_role('headmaster', 'HEADMASTER', $  caps);         }     }      public static function modify_menu() {         global $  submenu;         unset($  submenu['edit.php?post_type=teacher'][10]);     } } School::init();