array( 'slms_course', 'slms_courses' ), 'slms_unit' => array( 'slms_unit', 'slms_units' ), 'slms_lesson' => array( 'slms_lesson', 'slms_lessons' ), 'slms_quiz' => array( 'slms_quiz', 'slms_quizzes' ), ); /** * Post capability => the same capability for a post type (%s is its plural). * These are every primitive capability map_meta_cap() asks for. */ const FROM_POST_CAPS = array( 'edit_posts' => 'edit_%s', 'edit_others_posts' => 'edit_others_%s', 'edit_private_posts' => 'edit_private_%s', 'edit_published_posts' => 'edit_published_%s', 'publish_posts' => 'publish_%s', 'read_private_posts' => 'read_private_%s', 'delete_posts' => 'delete_%s', 'delete_others_posts' => 'delete_others_%s', 'delete_private_posts' => 'delete_private_%s', 'delete_published_posts' => 'delete_published_%s', ); public static function create_roles() { add_role( 'slms_student', __( 'Student', 'accessnow-lms' ), array( 'read' => true, ) ); $admin = get_role( 'administrator' ); if ( $admin ) { $admin->add_cap( 'manage_slms' ); $admin->add_cap( 'manage_slms_enrollments' ); $admin->add_cap( 'manage_slms_reports' ); foreach ( self::post_type_caps() as $cap ) { $admin->add_cap( $cap ); } } } public static function remove_roles() { remove_role( 'slms_student' ); $admin = get_role( 'administrator' ); if ( $admin ) { $admin->remove_cap( 'manage_slms' ); $admin->remove_cap( 'manage_slms_enrollments' ); $admin->remove_cap( 'manage_slms_reports' ); } self::remove_post_type_caps(); } /** * The arguments that give a post type its own capabilities. * * @param string $post_type One of POST_TYPES. * @return array */ public static function post_type_args( $post_type ) { return array( 'capability_type' => self::POST_TYPES[ $post_type ], 'map_meta_cap' => true, ); } /** * Every primitive capability of the four post types. * * @return string[] */ public static function post_type_caps() { $caps = array(); foreach ( self::POST_TYPES as $names ) { foreach ( self::FROM_POST_CAPS as $template ) { $caps[] = sprintf( $template, $names[1] ); } } return $caps; } /** * Give the roles that run the site's content (those that can edit others' posts: administrators, * editors) the course, unit, lesson and quiz capabilities matching their post capabilities (5.1.0). * * Until 5.1.0 the post types used the post capabilities, so authors and contributors could reach a * course's editor through "+ New" although the LMS menu never showed them anything (Martin, * 2026-10-18: LMS content stays with admins and editors). They get nothing now; an instructor role * is given course capabilities explicitly. * * Only adds: a capability a role was explicitly denied (false) is neither copied nor overwritten, * and running it twice changes nothing. Roles created later get none until they are given them. */ public static function grant_matching_post_caps() { foreach ( array_keys( wp_roles()->roles ) as $role_name ) { $role = get_role( $role_name ); if ( ! $role || empty( $role->capabilities['edit_others_posts'] ) ) { continue; } foreach ( self::FROM_POST_CAPS as $post_cap => $template ) { if ( empty( $role->capabilities[ $post_cap ] ) ) { continue; } foreach ( self::POST_TYPES as $names ) { $cap = sprintf( $template, $names[1] ); if ( ! array_key_exists( $cap, $role->capabilities ) ) { $role->add_cap( $cap ); } } } } } /** * Remove the post type capabilities from every role (uninstall). */ public static function remove_post_type_caps() { foreach ( array_keys( wp_roles()->roles ) as $role_name ) { $role = get_role( $role_name ); if ( ! $role ) { continue; } foreach ( self::post_type_caps() as $cap ) { if ( array_key_exists( $cap, $role->capabilities ) ) { $role->remove_cap( $cap ); } } } } /** * Whether the current user may see a lesson or quiz without being enrolled: LMS managers, and * anyone who can edit it (its author, an editor), so they can preview their own work. * * @param int $post_id Lesson or quiz ID. * @return bool */ public static function can_preview( $post_id ) { return current_user_can( 'manage_slms' ) || ( $post_id && current_user_can( 'edit_post', $post_id ) ); } /** * Whether the current user may make a post its parent (a lesson's unit, a quiz's lesson): they must * be able to edit it. The parent it already has is always kept, and 0 (no parent) is always allowed. * * @param int $new_parent Submitted parent ID. * @param int $current The parent stored now. * @return bool */ public static function can_use_parent( $new_parent, $current ) { $new_parent = (int) $new_parent; return 0 === $new_parent || (int) $current === $new_parent || current_user_can( 'edit_post', $new_parent ); } /** * Parent options for a meta box select: the posts the current user can edit, plus the current one. * * @param \WP_Post[] $posts Candidate parents. * @param int $current The parent stored now. * @return \WP_Post[] */ public static function filter_parent_options( $posts, $current ) { return array_values( array_filter( $posts, function ( $post ) use ( $current ) { return (int) $post->ID === (int) $current || current_user_can( 'edit_post', $post->ID ); } ) ); } }