Files
thalim-theme/inc/membres-helpers.php
2026-05-12 23:33:46 +02:00

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;
}