245 lines
9.7 KiB
PHP
245 lines
9.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Normalise a free-text research-domain field for use in a data-* attribute:
|
|
* converts <br> variants to \n and strips any remaining HTML tags.
|
|
*/
|
|
function thalim_sanitize_domaines( $raw ) {
|
|
// Normalise all <br> variants (including \r before them) to a newline
|
|
$text = preg_replace( '/\r?<br\s*\/?>/i', "\n", $raw );
|
|
// Strip any remaining HTML tags
|
|
$text = strip_tags( $text );
|
|
// Clean up excess blank lines / whitespace
|
|
$text = preg_replace( "/\n{3,}/", "\n\n", trim( $text ) );
|
|
return $text;
|
|
}
|
|
|
|
/**
|
|
* Build the display data array for a single user.
|
|
*/
|
|
function thalim_build_membre_data( $user ) {
|
|
$lang = thalim_current_language();
|
|
$status_parts = [];
|
|
$role_names = [];
|
|
for ( $n = 1; $n <= 3; $n++ ) {
|
|
$role_id = get_user_meta( $user->ID, 'role_' . $n, true );
|
|
if ( ! $role_id ) continue;
|
|
$term = get_term( intval( $role_id ), 'role' );
|
|
if ( ! $term || is_wp_error( $term ) ) continue;
|
|
$role_names[] = $term->name;
|
|
$override = thalim_bilingual( get_user_meta( $user->ID, 'affichage_du_statut_' . $n, true ) ?: '', $lang );
|
|
if ( $override ) {
|
|
$status_parts[] = $override;
|
|
} else {
|
|
$entry = $term->name;
|
|
$complement = thalim_bilingual( get_user_meta( $user->ID, 'complement_de_role_' . $n, true ) ?: '', $lang );
|
|
if ( $complement ) $entry .= ' ' . $complement;
|
|
$status_parts[] = $entry;
|
|
}
|
|
}
|
|
|
|
// Avatar (Simple Local Avatar with Gravatar fallback)
|
|
$avatar_url = thalim_get_user_avatar_url( $user->ID );
|
|
|
|
// Domaines de recherches: multiple usermeta rows, each is a post_tag term ID
|
|
$domaine_ids = get_user_meta( $user->ID, 'domaines_de_recherches', false );
|
|
$domaines = [];
|
|
foreach ( $domaine_ids as $term_id ) {
|
|
$term = get_term( intval( $term_id ), 'post_tag' );
|
|
if ( $term && ! is_wp_error( $term ) ) {
|
|
$domaines[] = $term->name;
|
|
}
|
|
}
|
|
|
|
return [
|
|
'display_name' => $user->display_name,
|
|
'sort_key' => thalim_get_sort_key( $user->ID, $user->display_name ),
|
|
'url' => get_author_posts_url( $user->ID ),
|
|
'status' => implode( ', ', $status_parts ),
|
|
'affiliation' => (function() use ($user) {
|
|
$v = get_user_meta( $user->ID, 'affiliation', true ) ?: '';
|
|
return strtolower( $v ) === 'autre'
|
|
? ( get_user_meta( $user->ID, 'affiliation_autre', true ) ?: '' )
|
|
: $v;
|
|
})(),
|
|
'role_names' => $role_names,
|
|
'avatar_url' => $avatar_url,
|
|
'domaines' => $domaines,
|
|
'autres_domaines' => thalim_sanitize_domaines( get_user_meta( $user->ID, 'autres_domaines_de_recherches', true ) ?: '' ),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Return all role taxonomy terms that are in use, sorted by name.
|
|
*/
|
|
function thalim_get_role_terms() {
|
|
$terms = get_terms( [ 'taxonomy' => 'role', 'hide_empty' => true, 'orderby' => 'name' ] );
|
|
if ( is_wp_error( $terms ) ) return [];
|
|
return array_values( array_map(
|
|
fn( $t ) => [ 'id' => $t->term_id, 'name' => $t->name ],
|
|
array_filter( $terms, fn( $t ) => ! in_array( mb_strtolower( $t->name, 'UTF-8' ), [ 'archive', 'à ranger' ], true ) )
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* Return all role term_ids set for a user (role_1, role_2, role_3).
|
|
*/
|
|
function thalim_get_user_role_ids( $user_id ) {
|
|
$ids = [];
|
|
for ( $n = 1; $n <= 3; $n++ ) {
|
|
$role_id = get_user_meta( $user_id, 'role_' . $n, true );
|
|
if ( $role_id ) $ids[] = intval( $role_id );
|
|
}
|
|
return $ids;
|
|
}
|
|
|
|
/**
|
|
* Sort key: first word of last_name user meta (handles compound last names like
|
|
* "Duclaux de l'Estoile" → "Duclaux"). Falls back to last word of display_name.
|
|
*/
|
|
function thalim_get_sort_key( $user_id, $display_name ) {
|
|
$last = get_user_meta( $user_id, 'last_name', true );
|
|
if ( $last ) {
|
|
$parts = explode( ' ', trim( $last ) );
|
|
return $parts[0];
|
|
}
|
|
$parts = explode( ' ', trim( $display_name ) );
|
|
return end( $parts );
|
|
}
|
|
|
|
/**
|
|
* Return all member groups for the /membres page.
|
|
* Each group: ['title' => string, 'members' => array of member data arrays].
|
|
* Empty groups are omitted.
|
|
*/
|
|
function thalim_get_membres_groups() {
|
|
// Fetch all users that have role_1 set
|
|
$users = get_users( [
|
|
'meta_key' => 'role_1',
|
|
'number' => -1,
|
|
] );
|
|
|
|
// Direction: read directeur and directeur_adjoint from "Le laboratoire" page
|
|
$labo_page = get_page_by_path( 'le-laboratoire' );
|
|
$directeur_id = $labo_page ? intval( get_post_meta( $labo_page->ID, 'directeur', true ) ) : 0;
|
|
$adjoint_id = $labo_page ? intval( get_post_meta( $labo_page->ID, 'directeur_adjoint', true ) ) : 0;
|
|
|
|
$direction_users = [];
|
|
foreach ( [ $directeur_id, $adjoint_id ] as $uid ) {
|
|
if ( $uid ) {
|
|
$u = get_userdata( $uid );
|
|
if ( $u ) $direction_users[] = $u;
|
|
}
|
|
}
|
|
|
|
// Pre-build member data for all relevant users (cache by ID)
|
|
$member_cache = [];
|
|
$all_users = array_merge( $users, $direction_users );
|
|
foreach ( $all_users as $user ) {
|
|
if ( ! isset( $member_cache[ $user->ID ] ) ) {
|
|
$member_cache[ $user->ID ] = thalim_build_membre_data( $user );
|
|
}
|
|
}
|
|
|
|
// Prepend direction title to status for director / deputy director
|
|
if ( $directeur_id && isset( $member_cache[ $directeur_id ] ) ) {
|
|
$existing = $member_cache[ $directeur_id ]['status'];
|
|
$member_cache[ $directeur_id ]['status'] = 'Directeur' . ( $existing ? ', ' . $existing : '' );
|
|
}
|
|
if ( $adjoint_id && isset( $member_cache[ $adjoint_id ] ) ) {
|
|
$existing = $member_cache[ $adjoint_id ]['status'];
|
|
$member_cache[ $adjoint_id ]['status'] = 'Directeur adjoint' . ( $existing ? ', ' . $existing : '' );
|
|
}
|
|
|
|
// Build a slug→ID map for the 'role' taxonomy so group definitions survive
|
|
// database migrations where auto-incremented term IDs change.
|
|
$slug_to_id = [];
|
|
foreach ( get_terms( [ 'taxonomy' => 'role', 'hide_empty' => false ] ) as $term ) {
|
|
$slug_to_id[ $term->slug ] = $term->term_id;
|
|
}
|
|
$by_slug = fn( ...$slugs ) => array_values(
|
|
array_filter( array_map( fn( $s ) => $slug_to_id[ $s ] ?? null, $slugs ) )
|
|
);
|
|
|
|
// Group definitions (title => role slugs that qualify a user for membership)
|
|
$group_definitions = [
|
|
'Chercheuses et chercheurs CNRS' => $by_slug( 'directeur-de-recherche', 'charge-de-recherche' ),
|
|
'Enseignantes-chercheuses et enseignants-chercheurs' => $by_slug( 'professeur', 'maitre-de-conferences' ),
|
|
'Doctorantes et doctorants' => $by_slug( 'doctorant' ),
|
|
'Docteures et docteurs' => $by_slug( 'docteur' ),
|
|
'Postdoctorantes et postdoctorants' => $by_slug( 'postdoctorant' ),
|
|
'Personnel contractuel' => $by_slug( 'personnel-contractuel' ),
|
|
"Personnel d'accompagnement à la recherche" => $by_slug( 'personnel-technique' ),
|
|
'Membres associées et membres associés' => $by_slug( 'membre-associe' ),
|
|
'Anciennes et anciens membres' => $by_slug( 'anciens-membres' ),
|
|
];
|
|
|
|
$groups = [];
|
|
|
|
// Direction group first: directeur before directeur adjoint
|
|
$direction_members = [];
|
|
if ( $directeur_id && isset( $member_cache[ $directeur_id ] ) ) {
|
|
$direction_members[] = $member_cache[ $directeur_id ];
|
|
}
|
|
if ( $adjoint_id && isset( $member_cache[ $adjoint_id ] ) ) {
|
|
$direction_members[] = $member_cache[ $adjoint_id ];
|
|
}
|
|
if ( ! empty( $direction_members ) ) {
|
|
$groups[] = [
|
|
'title' => 'Direction',
|
|
'members' => $direction_members,
|
|
'fixed_order' => true,
|
|
];
|
|
}
|
|
|
|
// Role-based groups (a user appears in every group that matches any of their roles)
|
|
foreach ( $group_definitions as $title => $term_ids ) {
|
|
$group_members = [];
|
|
foreach ( $users as $user ) {
|
|
$user_role_ids = thalim_get_user_role_ids( $user->ID );
|
|
if ( array_intersect( $term_ids, $user_role_ids ) ) {
|
|
$group_members[] = $member_cache[ $user->ID ];
|
|
}
|
|
}
|
|
|
|
if ( empty( $group_members ) ) continue;
|
|
|
|
// Sort alphabetically by last name, accent- and case-insensitive (fr locale)
|
|
static $collator = null;
|
|
if ( $collator === null ) {
|
|
$collator = class_exists( 'Collator' ) ? new Collator( 'fr_FR' ) : false;
|
|
if ( $collator ) $collator->setStrength( Collator::PRIMARY );
|
|
}
|
|
usort( $group_members, function( $a, $b ) use ( $collator ) {
|
|
$la = $a['sort_key'];
|
|
$lb = $b['sort_key'];
|
|
if ( $collator ) return $collator->compare( $la, $lb );
|
|
return strcmp( mb_strtolower( $la, 'UTF-8' ), mb_strtolower( $lb, 'UTF-8' ) );
|
|
} );
|
|
|
|
// In "Personnel d'accompagnement", place "Gestion et pilotage" first
|
|
$fixed = false;
|
|
if ( $title === "Personnel d'accompagnement à la recherche" ) {
|
|
$priority = [];
|
|
$rest = [];
|
|
foreach ( $group_members as $m ) {
|
|
if ( stripos( $m['status'], 'Gestion et pilotage' ) !== false ) {
|
|
$priority[] = $m;
|
|
} else {
|
|
$rest[] = $m;
|
|
}
|
|
}
|
|
$group_members = array_merge( $priority, $rest );
|
|
$fixed = true;
|
|
}
|
|
|
|
$groups[] = [
|
|
'title' => $title,
|
|
'members' => $group_members,
|
|
'fixed_order' => $fixed,
|
|
];
|
|
}
|
|
|
|
return $groups;
|
|
}
|