}> */ function academiccrew_project_members_by_role( int $project_id ): array { $raw = get_post_meta( $project_id, '_acc_linked_members', true ); if ( ! is_array( $raw ) || empty( $raw ) ) { return []; } $labels = [ 'pi' => __( 'Principal Investigator', 'academiccrew' ), 'co-pi' => __( 'Co-PI', 'academiccrew' ), 'researcher' => __( 'Researcher', 'academiccrew' ), 'phd-student' => __( 'PhD Student', 'academiccrew' ), 'collaborator' => __( 'Collaborator', 'academiccrew' ), ]; $grouped = []; foreach ( $raw as $entry ) { // Normalise: new format [['member_id' => X, 'role' => Y]] or old flat int[]. if ( is_array( $entry ) && isset( $entry['member_id'] ) ) { $mid = (int) $entry['member_id']; $role = (string) ( $entry['role'] ?? 'collaborator' ); } elseif ( is_numeric( $entry ) && (int) $entry > 0 ) { $mid = (int) $entry; $role = 'collaborator'; } else { continue; // malformed entry } // HARD CHECK — must be a published academiccrew_member post. if ( get_post_type( $mid ) !== 'academiccrew_member' || get_post_status( $mid ) !== 'publish' ) { continue; } if ( ! isset( $grouped[ $role ] ) ) { $grouped[ $role ] = [ 'label' => $labels[ $role ] ?? ucwords( str_replace( '-', ' ', $role ) ), 'people' => [], ]; } $grouped[ $role ]['people'][] = $mid; } // Return in canonical role order, skipping empty groups. $sorted = []; foreach ( array_keys( $labels ) as $r ) { if ( isset( $grouped[ $r ] ) ) { $sorted[ $r ] = $grouped[ $r ]; } } return $sorted; } /** * Returns 1–2 uppercase initials from a academiccrew_member post title. * * @param int $id academiccrew_member post ID (already validated as such). */ function academiccrew_person_initials( int $id ): string { $name = (string) get_the_title( $id ); $parts = array_values( array_filter( explode( ' ', trim( $name ) ) ) ); if ( count( $parts ) >= 2 ) { return mb_strtoupper( mb_substr( $parts[0], 0, 1 ) . mb_substr( $parts[ count( $parts ) - 1 ], 0, 1 ) ); } return mb_strtoupper( mb_substr( $name, 0, 2 ) ); }