is_main_query() || current_user_can( 'edit_others_posts' ) ) { return; } global $user_ID, $wpdb; // Posts where the user is listed as membre or autre_membre. $membre_ids = array_map( 'intval', (array) $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_key IN ('membres', 'autre_membres') AND meta_value = %s", $user_ID ) ) ); if ( empty( $membre_ids ) ) { // Fast path: no membre posts, use simple author filter. $query->set( 'author', $user_ID ); return; } // Posts authored by this user. $authored_ids = array_map( 'intval', (array) $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_author = %d", $user_ID ) ) ); $all_ids = array_unique( array_merge( $authored_ids, $membre_ids ) ); // post__in with [0] returns nothing when the combined set is empty. $query->set( 'post__in', empty( $all_ids ) ? [ 0 ] : $all_ids ); } add_action( 'pre_get_posts', 'restrict_contributor_posts' ); /** * Let contributors listed as membres/autre_membres on a post edit it. * * user_has_cap modifies capabilities only for this single check — * it does not permanently alter the user's capability set. */ function thalim_membres_can_edit_post( $allcaps, $caps, $args, $user ) { // Editors and above already have edit_others_posts — nothing to do. if ( ! empty( $allcaps['edit_others_posts'] ) ) { return $allcaps; } if ( empty( $args[0] ) ) { return $allcaps; } $cap = $args[0]; // Meta caps that carry a post ID in $args[2] (e.g. wp-admin/post.php load). $meta_caps_with_id = [ 'edit_post', 'edit_page' ]; // Primitive caps called during the admin save flow *without* a // post_id (e.g. wp-admin/includes/post.php:76 checks edit_others_posts // directly when $post_author !== current user). We infer the post_id from // the request so we can still authorize membres per-post. // // NOTE: publish_posts / publish_pages are intentionally NOT in this list — // contributors listed in `membres` must be able to edit (incl. published) // posts of the lab, but only editors/admins should be able to publish. $primitive_caps_in_save_flow = [ 'edit_others_posts', 'edit_others_pages', 'edit_published_posts', 'edit_published_pages', ]; $post_id = 0; if ( in_array( $cap, $meta_caps_with_id, true ) && ! empty( $args[2] ) ) { $post_id = (int) $args[2]; } elseif ( in_array( $cap, $primitive_caps_in_save_flow, true ) ) { $post_id = (int) ( $_POST['post_ID'] ?? $_REQUEST['post'] ?? 0 ); } if ( ! $post_id ) { return $allcaps; } $user_id = $user->ID; $membre_ids = array_map( 'intval', array_merge( (array) get_post_meta( $post_id, 'membres', false ), (array) get_post_meta( $post_id, 'autre_membres', false ) ) ); if ( in_array( $user_id, $membre_ids, true ) ) { // Grant every primitive cap mapped for this check // (e.g. edit_others_posts, edit_published_posts). foreach ( $caps as $c ) { $allcaps[ $c ] = true; } } return $allcaps; } add_filter( 'user_has_cap', 'thalim_membres_can_edit_post', 10, 4 ); // Prevent WP_Posts_List_Table from auto-redirecting contributors to the "Mine" // view. The constructor sets $_GET['author'] = current_user_id() when the user // lacks edit_others_posts and no other filter is active. Setting all_posts=1 // before the list table is constructed short-circuits that condition. add_action( 'load-edit.php', function () { if ( current_user_can( 'edit_others_posts' ) ) { return; } if ( empty( $_REQUEST['post_status'] ) && empty( $_REQUEST['all_posts'] ) && empty( $_REQUEST['author'] ) && empty( $_REQUEST['show_sticky'] ) ) { $_GET['all_posts'] = 1; $_REQUEST['all_posts'] = 1; } } ); // Adjust post-status counts so contributors see only posts they can access // (posts they authored + posts listed in membres/autre_membres), not all posts. // The wp_count_posts filter runs even on cached values, so it won't pollute // the shared cache. add_filter( 'wp_count_posts', function ( $counts, $type, $perm ) { if ( ! is_admin() || current_user_can( 'edit_others_posts' ) ) { return $counts; } global $wpdb; $user_id = get_current_user_id(); $results = $wpdb->get_results( $wpdb->prepare( "SELECT post_status, COUNT(*) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s AND ID IN ( SELECT ID FROM {$wpdb->posts} WHERE post_author = %d AND post_type = %s UNION SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key IN ('membres', 'autre_membres') AND meta_value = %s ) GROUP BY post_status", $type, $user_id, $type, (string) $user_id ), ARRAY_A ); $new_counts = array_fill_keys( get_post_stati(), 0 ); foreach ( $results as $row ) { $new_counts[ $row['post_status'] ] = (int) $row['num_posts']; } return (object) $new_counts; }, 10, 3 ); // ── "Vie du labo" — restricted to logged-in users ──── add_action( 'pre_get_posts', function( $query ) { if ( is_user_logged_in() ) return; $vie_du_labo = thalim_cat_id( 'vie-du-labo' ); if ( ! $vie_du_labo ) return; $excluded = $query->get( 'category__not_in' ); if ( ! is_array( $excluded ) ) $excluded = $excluded ? [ $excluded ] : []; if ( ! in_array( $vie_du_labo, $excluded ) ) { $excluded[] = $vie_du_labo; $query->set( 'category__not_in', $excluded ); } } ); add_action( 'template_redirect', function() { if ( ! is_user_logged_in() && is_category( thalim_cat_id( 'vie-du-labo' ) ) ) { wp_safe_redirect( home_url( '/' ) ); exit; } } ); add_filter( 'wp_nav_menu_objects', function( $items, $args ) { if ( is_user_logged_in() ) return $items; $vie_du_labo = thalim_cat_id( 'vie-du-labo' ); return array_values( array_filter( $items, function( $item ) use ( $vie_du_labo ) { if ( $item->object === 'category' && (int) $item->object_id === $vie_du_labo ) return false; if ( strpos( $item->url, 'vie-du-labo' ) !== false ) return false; return true; } ) ); }, 10, 2 ); // Non-admins: hide dashboard and tools menu, redirect to posts list add_action( 'admin_menu', function() { if ( ! current_user_can( 'manage_options' ) ) { remove_menu_page( 'tools.php' ); remove_menu_page( 'index.php' ); } } ); // Redirect non-admins away from dashboard to their posts list add_action( 'admin_init', function() { if ( current_user_can( 'manage_options' ) ) return; global $pagenow; if ( $pagenow === 'index.php' ) { wp_safe_redirect( admin_url( 'edit.php' ) ); exit; } } ); // After login, send non-admins to posts list instead of dashboard add_filter( 'login_redirect', function( $redirect_to, $requested, $user ) { if ( ! is_wp_error( $user ) && ! $user->has_cap( 'manage_options' ) ) { return admin_url( 'edit.php' ); } return $redirect_to; }, 10, 3 );