diff --git a/inc/access-control.php b/inc/access-control.php index b934368..d866e97 100644 --- a/inc/access-control.php +++ b/inc/access-control.php @@ -8,8 +8,47 @@ * - redirections login/dashboard des non-admins. */ +/** + * Séances qu'un utilisateur peut éditer par héritage : toutes les séances + * listées (meta Pods `seances`) dans un séminaire dont il est l'auteur OU où + * il figure en membres/autre_membres. Mémoïsé par utilisateur — user_has_cap + * est appelé de très nombreuses fois par chargement de page admin. + */ +function thalim_user_editable_seance_ids( int $user_id ): array { + static $cache = []; + if ( isset( $cache[ $user_id ] ) ) { + return $cache[ $user_id ]; + } + + global $wpdb; + + // Séminaires éditables : auteur OU membre listé. + $seminaire_ids = array_map( 'intval', (array) $wpdb->get_col( $wpdb->prepare( + "SELECT ID FROM {$wpdb->posts} WHERE post_author = %d + UNION + SELECT post_id FROM {$wpdb->postmeta} + WHERE meta_key IN ('membres', 'autre_membres') AND meta_value = %s", + $user_id, + (string) $user_id + ) ) ); + + if ( empty( $seminaire_ids ) ) { + return $cache[ $user_id ] = []; + } + + // Séances listées par ces séminaires. + $in = implode( ',', $seminaire_ids ); + $seance_ids = array_map( 'intval', (array) $wpdb->get_col( + "SELECT meta_value FROM {$wpdb->postmeta} + WHERE meta_key = 'seances' AND post_id IN ($in)" + ) ); + + return $cache[ $user_id ] = array_values( array_unique( $seance_ids ) ); +} + // Restrict Contributors to see only their own posts in admin, -// but also include posts where they appear in membres/autre_membres. +// but also include posts where they appear in membres/autre_membres, +// plus les séances des séminaires qu'ils peuvent éditer. function restrict_contributor_posts( $query ) { if ( ! is_admin() || ! $query->is_main_query() || current_user_can( 'edit_others_posts' ) ) { return; @@ -26,8 +65,11 @@ function restrict_contributor_posts( $query ) { ) ) ); - if ( empty( $membre_ids ) ) { - // Fast path: no membre posts, use simple author filter. + // Séances héritées des séminaires que l'utilisateur peut éditer. + $seance_ids = thalim_user_editable_seance_ids( $user_ID ); + + if ( empty( $membre_ids ) && empty( $seance_ids ) ) { + // Fast path: no membre/séance posts, use simple author filter. $query->set( 'author', $user_ID ); return; } @@ -40,7 +82,7 @@ function restrict_contributor_posts( $query ) { ) ) ); - $all_ids = array_unique( array_merge( $authored_ids, $membre_ids ) ); + $all_ids = array_unique( array_merge( $authored_ids, $membre_ids, $seance_ids ) ); // post__in with [0] returns nothing when the combined set is empty. $query->set( 'post__in', empty( $all_ids ) ? [ 0 ] : $all_ids ); @@ -104,7 +146,15 @@ function thalim_membres_can_edit_post( $allcaps, $caps, $args, $user ) { ) ); - if ( in_array( $user_id, $membre_ids, true ) ) { + $can_edit = in_array( $user_id, $membre_ids, true ); + + // Séance de séminaire : hérite des droits d'édition du séminaire parent + // (auteur ou membre du séminaire qui la liste dans `seances`). + if ( ! $can_edit ) { + $can_edit = in_array( $post_id, thalim_user_editable_seance_ids( $user_id ), true ); + } + + if ( $can_edit ) { // Grant every primitive cap mapped for this check // (e.g. edit_others_posts, edit_published_posts). foreach ( $caps as $c ) { @@ -147,6 +197,12 @@ add_filter( 'wp_count_posts', function ( $counts, $type, $perm ) { global $wpdb; $user_id = get_current_user_id(); + // Séances héritées des séminaires éditables (liste d'IDs entiers, sûre à interpoler). + $seance_ids = thalim_user_editable_seance_ids( $user_id ); + $seance_union = $seance_ids + ? ' UNION SELECT ' . implode( ' AS ID UNION SELECT ', $seance_ids ) . ' AS ID' + : ''; + $results = $wpdb->get_results( $wpdb->prepare( "SELECT post_status, COUNT(*) AS num_posts @@ -158,6 +214,7 @@ add_filter( 'wp_count_posts', function ( $counts, $type, $perm ) { UNION SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key IN ('membres', 'autre_membres') AND meta_value = %s + $seance_union ) GROUP BY post_status", $type, @@ -206,12 +263,16 @@ add_filter( 'wp_nav_menu_objects', function( $items, $args ) { } ) ); }, 10, 2 ); -// Non-admins: hide dashboard and tools menu, redirect to posts list +// Non-admins: hide dashboard, redirect to posts list. +// Outils reste visible pour les éditeurs (cap edit_others_posts) : les pages +// HAL Import / Newsletter y sont gatées sur cette même cap. add_action( 'admin_menu', function() { if ( ! current_user_can( 'manage_options' ) ) { - remove_menu_page( 'tools.php' ); remove_menu_page( 'index.php' ); } + if ( ! current_user_can( 'edit_others_posts' ) ) { + remove_menu_page( 'tools.php' ); + } } ); // Redirect non-admins away from dashboard to their posts list