Initial commit
This commit is contained in:
48
inc/admin-users-filter.php
Normal file
48
inc/admin-users-filter.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Add a "Statut" filter dropdown to /wp-admin/users.php.
|
||||
* Filters by the custom "role" taxonomy stored in user meta keys role_1/role_2/role_3.
|
||||
*/
|
||||
|
||||
add_action( 'restrict_manage_users', function() {
|
||||
$terms = get_terms( [ 'taxonomy' => 'role', 'hide_empty' => true, 'orderby' => 'name' ] );
|
||||
if ( is_wp_error( $terms ) || empty( $terms ) ) return;
|
||||
|
||||
$selected = isset( $_GET['thalim_statut'] ) ? intval( $_GET['thalim_statut'] ) : 0;
|
||||
?>
|
||||
<select id="thalim_statut_filter">
|
||||
<option value=""><?php esc_html_e( 'Tous les statuts', 'thalim' ); ?></option>
|
||||
<?php foreach ( $terms as $term ) : ?>
|
||||
<option value="<?php echo esc_attr( $term->term_id ); ?>"<?php selected( $selected, $term->term_id ); ?>>
|
||||
<?php echo esc_html( $term->name ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<button type="button" class="button" id="thalim_statut_go"><?php esc_html_e( 'Filtrer', 'thalim' ); ?></button>
|
||||
<script>
|
||||
document.getElementById('thalim_statut_go').addEventListener('click', function() {
|
||||
var v = document.getElementById('thalim_statut_filter').value;
|
||||
var url = new URL(window.location.href);
|
||||
url.searchParams.delete('paged');
|
||||
if (v) url.searchParams.set('thalim_statut', v);
|
||||
else url.searchParams.delete('thalim_statut');
|
||||
window.location.href = url.toString();
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
} );
|
||||
|
||||
add_action( 'pre_get_users', function( WP_User_Query $query ) {
|
||||
if ( ! is_admin() ) return;
|
||||
|
||||
$term_id = isset( $_GET['thalim_statut'] ) ? intval( $_GET['thalim_statut'] ) : 0;
|
||||
if ( ! $term_id ) return;
|
||||
|
||||
$query->set( 'meta_query', [
|
||||
'relation' => 'OR',
|
||||
[ 'key' => 'role_1', 'value' => $term_id, 'compare' => '=' ],
|
||||
[ 'key' => 'role_2', 'value' => $term_id, 'compare' => '=' ],
|
||||
[ 'key' => 'role_3', 'value' => $term_id, 'compare' => '=' ],
|
||||
] );
|
||||
} );
|
||||
250
inc/author-helpers.php
Normal file
250
inc/author-helpers.php
Normal file
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Resolve all profile data for a member/author into a display-ready array.
|
||||
*/
|
||||
function thalim_get_author_data($user_id) {
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) return [];
|
||||
|
||||
$lang = thalim_current_language();
|
||||
|
||||
// --- Avatar (Simple Local Avatar with Gravatar fallback) ---
|
||||
$avatar_url = thalim_get_user_avatar_url( $user_id );
|
||||
|
||||
// --- Role (taxonomy 'role') ---
|
||||
$role_id = get_user_meta($user_id, 'role_1', true);
|
||||
$role_label = '';
|
||||
if ($role_id) {
|
||||
$role_term = get_term(intval($role_id), 'role');
|
||||
if ($role_term && !is_wp_error($role_term)) {
|
||||
$override = thalim_bilingual(get_user_meta($user_id, 'affichage_du_statut_1', true) ?: '', $lang);
|
||||
$role_label = $override ?: $role_term->name;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Direction title (read 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;
|
||||
if ($user_id === $directeur_id) {
|
||||
$role_label = 'Directeur' . ($role_label ? ', ' . $role_label : '');
|
||||
} elseif ($user_id === $adjoint_id) {
|
||||
$role_label = 'Directeur adjoint' . ($role_label ? ', ' . $role_label : '');
|
||||
}
|
||||
|
||||
// --- Domaines de recherches (multiple usermeta rows with post_tag IDs) ---
|
||||
$domaine_ids = get_user_meta($user_id, 'domaines_de_recherches', false);
|
||||
$domaines_tags = [];
|
||||
foreach ($domaine_ids as $tag_id) {
|
||||
if (!$tag_id) continue;
|
||||
$term = get_term(intval($tag_id), 'post_tag');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$link = get_term_link($term);
|
||||
if (!is_wp_error($link)) {
|
||||
$domaines_tags[] = ['name' => thalim_bilingual($term->name, $lang), 'url' => $link];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Axes thématiques (multiple usermeta rows) ---
|
||||
$axe_ids = get_user_meta($user_id, 'axes_thematiques', false);
|
||||
$axes = [];
|
||||
foreach ($axe_ids as $axe_id) {
|
||||
$term = get_term(intval($axe_id), 'axe_thematique');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$axes[] = [
|
||||
'name' => thalim_bilingual($term->name, $lang),
|
||||
'url' => get_term_link($term),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- External links (up to 4) ---
|
||||
$liens_externes = [];
|
||||
for ($i = 1; $i <= 4; $i++) {
|
||||
$url = get_user_meta($user_id, 'lien_externe_' . $i, true);
|
||||
if ($url) {
|
||||
$titre = thalim_bilingual(get_user_meta($user_id, 'titre_du_lien_' . $i, true) ?: '', $lang);
|
||||
if (!$titre) {
|
||||
$host = parse_url($url, PHP_URL_HOST) ?: $url;
|
||||
$parts = explode('.', $host);
|
||||
$titre = count($parts) >= 2 ? implode('.', array_slice($parts, -2)) : $host;
|
||||
}
|
||||
$liens_externes[] = ['url' => $url, 'titre' => $titre];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Documents (multiple usermeta rows with attachment IDs) ---
|
||||
$doc_ids = get_user_meta($user_id, 'documents', false);
|
||||
$documents = [];
|
||||
foreach ($doc_ids as $doc_id) {
|
||||
$url = wp_get_attachment_url(intval($doc_id));
|
||||
if ($url) {
|
||||
$documents[] = [
|
||||
'url' => $url,
|
||||
'title' => get_the_title($doc_id) ?: basename(get_attached_file($doc_id)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Thesis director (THALIM member — stored as user ID) ---
|
||||
$directeur_id = get_user_meta($user_id, 'directeur_de_these_thalim', true);
|
||||
$directeur_thalim = null;
|
||||
if ($directeur_id) {
|
||||
$dir_user = get_userdata(intval($directeur_id));
|
||||
if ($dir_user) {
|
||||
$directeur_thalim = [
|
||||
'name' => $dir_user->display_name,
|
||||
'url' => get_author_posts_url(intval($directeur_id)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Email visibility ---
|
||||
$is_ancien = isset($role_term) && $role_term && $role_term->slug === 'anciens-membres';
|
||||
$show_email = !$is_ancien && get_user_meta($user_id, 'afficher_ladresse_mail_sur_le_profil', true);
|
||||
|
||||
return [
|
||||
'display_name' => $user->display_name,
|
||||
'avatar_url' => $avatar_url,
|
||||
'role_label' => $role_label,
|
||||
'role_complement' => thalim_bilingual(get_user_meta($user_id, 'complement_de_role_1', true) ?: '', $lang),
|
||||
'affiliation' => (function() use ($user_id, $lang) {
|
||||
$v = get_user_meta($user_id, 'affiliation', true) ?: '';
|
||||
return strtolower($v) === 'autre'
|
||||
? thalim_bilingual(get_user_meta($user_id, 'affiliation_autre', true) ?: '', $lang)
|
||||
: $v;
|
||||
})(),
|
||||
'bio' => wpautop( make_clickable( get_user_meta($user_id, 'biographie', true) ?: '' ) ),
|
||||
'bio_en' => wpautop( make_clickable( get_user_meta($user_id, 'biographie_en', true) ?: '' ) ),
|
||||
'domaines_tags' => $domaines_tags,
|
||||
'domaines' => wpautop( make_clickable( get_user_meta($user_id, 'autres_domaines_de_recherches', true) ?: '' ) ),
|
||||
'domaines_en' => wpautop( make_clickable( get_user_meta($user_id, 'autres_domaines_de_recherches_en', true) ?: '' ) ),
|
||||
'recherches' => wpautop( get_user_meta($user_id, 'recherches_en_cours', true) ?: '' ),
|
||||
'recherches_en' => wpautop( get_user_meta($user_id, 'recherches_en_cours_en', true) ?: '' ),
|
||||
'axes' => $axes,
|
||||
'titre_these' => thalim_bilingual(get_user_meta($user_id, 'titre_de_these', true) ?: '', $lang),
|
||||
'date_soutenance' => get_user_meta($user_id, 'date_de_soutenance', true) ?: '',
|
||||
'directeur_thalim'=> $directeur_thalim,
|
||||
'autre_directeur' => get_user_meta($user_id, 'autre_directeur_de_these', true) ?: '',
|
||||
'resume_these' => wpautop( get_user_meta($user_id, 'resume_de_la_these', true) ?: '' ),
|
||||
'resume_these_en' => wpautop( get_user_meta($user_id, 'resume_de_la_these_en', true) ?: '' ),
|
||||
'email' => $show_email ? $user->user_email : '',
|
||||
'liens_externes' => $liens_externes,
|
||||
'documents' => $documents,
|
||||
'hal_publications_url' => (function() use ($user_id) {
|
||||
$hal_id = get_user_meta($user_id, 'identifiant_hal', true) ?: '';
|
||||
return $hal_id
|
||||
? 'https://hal.science/search/index/?qa[authIdHal_s][]=' . rawurlencode($hal_id) . '&sort=publicationDate_tdate+desc'
|
||||
: '';
|
||||
})(),
|
||||
'user_since' => date_i18n('d/m/Y', strtotime($user->user_registered)),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Query all posts linked to a member and group them by primary category.
|
||||
* Returns an array sorted by post count (descending).
|
||||
*/
|
||||
function thalim_get_author_posts_by_category($user_id) {
|
||||
$excluded_cats = [12, 31]; // séances de séminaire, etc.
|
||||
$lang = thalim_current_language();
|
||||
|
||||
$posts = Timber::get_posts([
|
||||
'post_type' => 'post',
|
||||
'posts_per_page' => -1,
|
||||
'meta_query' => [
|
||||
'relation' => 'OR',
|
||||
[
|
||||
'key' => 'membres',
|
||||
'value' => $user_id,
|
||||
],
|
||||
[
|
||||
'key' => 'autre_membres',
|
||||
'value' => $user_id,
|
||||
],
|
||||
],
|
||||
'thalim_event_date_order' => true,
|
||||
'lang' => '',
|
||||
]);
|
||||
|
||||
$groups = [];
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$categories = wp_get_post_categories($post->ID, ['fields' => 'all']);
|
||||
$primary_cat = null;
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
if (in_array($cat->term_id, $excluded_cats)) continue;
|
||||
$primary_cat = $cat;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$primary_cat) continue;
|
||||
|
||||
$cat_id = $primary_cat->term_id;
|
||||
if (!isset($groups[$cat_id])) {
|
||||
// A top-level category with subcategories → these posts are "Autres"
|
||||
$is_autres = false;
|
||||
if ($primary_cat->parent == 0) {
|
||||
$subcats = get_categories(['parent' => $cat_id, 'hide_empty' => true, 'exclude' => $excluded_cats]);
|
||||
$is_autres = !empty($subcats);
|
||||
}
|
||||
$groups[$cat_id] = [
|
||||
'cat_id' => $cat_id,
|
||||
'cat_name' => $is_autres
|
||||
? ($lang === 'en' ? 'Other ' : 'Autres ') . thalim_cat_name($primary_cat, $lang)
|
||||
: thalim_cat_name($primary_cat, $lang),
|
||||
'cat_url' => $is_autres
|
||||
? trailingslashit(get_category_link($cat_id)) . 'autres/'
|
||||
: get_category_link($cat_id),
|
||||
'posts' => [],
|
||||
];
|
||||
}
|
||||
$groups[$cat_id]['posts'][] = $post;
|
||||
}
|
||||
|
||||
// Séances de séminaire — dedicated group. Posts in cat 12 where the member
|
||||
// is listed in `membres`/`autre_membres`. Cards use the parent séminaire
|
||||
// permalink with a #seance-{ID} hash (see thalim_get_card_data).
|
||||
$seances = Timber::get_posts([
|
||||
'post_type' => 'post',
|
||||
'posts_per_page' => -1,
|
||||
'category__in' => [12],
|
||||
'meta_query' => [
|
||||
'relation' => 'OR',
|
||||
[ 'key' => 'membres', 'value' => $user_id ],
|
||||
[ 'key' => 'autre_membres', 'value' => $user_id ],
|
||||
],
|
||||
'thalim_event_date_order' => true,
|
||||
'lang' => '',
|
||||
]);
|
||||
if (count($seances) > 0) {
|
||||
$seance_cat = get_term(12, 'category');
|
||||
$groups[12] = [
|
||||
'cat_id' => 12,
|
||||
'cat_name' => $seance_cat && !is_wp_error($seance_cat)
|
||||
? thalim_cat_name($seance_cat, $lang)
|
||||
: ($lang === 'en' ? 'Seminar sessions' : 'Séances de séminaire'),
|
||||
'cat_url' => get_category_link(12),
|
||||
'posts' => $seances,
|
||||
];
|
||||
}
|
||||
|
||||
// Resolve card data and sort by count descending
|
||||
foreach ($groups as &$group) {
|
||||
$group['cards'] = thalim_get_cards_data($group['posts']);
|
||||
}
|
||||
unset($group);
|
||||
|
||||
uasort($groups, function($a, $b) {
|
||||
$oa = (int) get_term_meta($a['cat_id'], 'ordre_profil', true) ?: 999;
|
||||
$ob = (int) get_term_meta($b['cat_id'], 'ordre_profil', true) ?: 999;
|
||||
return $oa !== $ob
|
||||
? $oa <=> $ob
|
||||
: count($b['posts']) <=> count($a['posts']);
|
||||
});
|
||||
|
||||
return array_values($groups);
|
||||
}
|
||||
244
inc/membres-helpers.php
Normal file
244
inc/membres-helpers.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?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;
|
||||
}
|
||||
94
inc/pods-conditional-required.php
Normal file
94
inc/pods-conditional-required.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* Désactiver le required des champs masqués par la logique conditionnelle de Pods.
|
||||
*
|
||||
* Pods ne prend pas en compte sa propre logique conditionnelle lors de la
|
||||
* validation serveur des champs requis. Ce filtre corrige ce comportement
|
||||
* pour le pod "post".
|
||||
*/
|
||||
add_filter( 'pods_api_pre_save_pod_item_post', 'thalim_skip_required_for_hidden_fields', 10, 3 );
|
||||
|
||||
function thalim_skip_required_for_hidden_fields( $pieces, $is_new_item, $id ) {
|
||||
if ( empty( $pieces['fields'] ) ) {
|
||||
return $pieces;
|
||||
}
|
||||
|
||||
// Récupérer les valeurs actuelles des champs pour évaluer la logique conditionnelle
|
||||
$field_values = [];
|
||||
foreach ( $pieces['fields'] as $name => $field ) {
|
||||
$field_values[ $name ] = isset( $field['value'] ) ? $field['value'] : '';
|
||||
}
|
||||
// Pour un post existant, si un champ n'a pas été soumis explicitement via
|
||||
// pods_meta_* (ex. Pods DFV React en éditeur classique), remplir sa valeur
|
||||
// depuis la BDD. Cela corrige à la fois :
|
||||
// - la validation du champ lui-même (pieces['fields']['value'])
|
||||
// - l'évaluation de la logique conditionnelle des autres champs ($field_values)
|
||||
if ( ! $is_new_item && $id ) {
|
||||
foreach ( $pieces['fields'] as $name => $field ) {
|
||||
// Skip pick/file/avatar fields: their value format in $pieces is complex
|
||||
// and get_post_meta returns a raw value that corrupts Pods' pick processing.
|
||||
// These fields are always submitted via POST by Pods DFV React.
|
||||
$field_type = pods_v( 'type', $field, '' );
|
||||
if ( in_array( $field_type, [ 'pick', 'file', 'avatar' ], true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$current_val = isset( $field['value'] ) ? $field['value'] : '';
|
||||
if ( ( '' === $current_val || null === $current_val ) && ! isset( $_POST[ 'pods_meta_' . $name ] ) ) {
|
||||
$db_val = get_post_meta( (int) $id, $name, true );
|
||||
if ( '' !== $db_val && null !== $db_val ) {
|
||||
$pieces['fields'][ $name ]['value'] = $db_val;
|
||||
$field_values[ $name ] = $db_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $pieces['fields'] as $field_name => $field_data ) {
|
||||
// Ne traiter que les champs required
|
||||
$required = is_object( $field_data ) && method_exists( $field_data, 'get_field_object' )
|
||||
? (int) $field_data->get_field_object()->get_arg( 'required', 0 )
|
||||
: (int) pods_v( 'required', $field_data, 0 );
|
||||
|
||||
if ( 1 !== $required ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Récupérer la logique conditionnelle
|
||||
$conditional_logic = null;
|
||||
|
||||
if ( is_object( $field_data ) && method_exists( $field_data, 'get_field_object' ) ) {
|
||||
$conditional_logic = $field_data->get_field_object()->get_conditional_logic();
|
||||
}
|
||||
|
||||
// Fallback : charger le champ via l'API Pods
|
||||
if ( ! $conditional_logic ) {
|
||||
$field_obj = pods_api()->load_field( [
|
||||
'name' => $field_name,
|
||||
'pod' => 'post',
|
||||
] );
|
||||
|
||||
if ( $field_obj && method_exists( $field_obj, 'get_conditional_logic' ) ) {
|
||||
$conditional_logic = $field_obj->get_conditional_logic();
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $conditional_logic ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Évaluer si le champ est visible avec les valeurs actuelles
|
||||
if ( ! $conditional_logic->is_visible( $field_values ) ) {
|
||||
// Le champ est masqué → désactiver le required
|
||||
if ( is_object( $field_data ) && method_exists( $field_data, 'get_field_object' ) ) {
|
||||
$field_data->get_field_object()->set_arg( 'required', 0 );
|
||||
}
|
||||
$pieces['fields'][ $field_name ]['required'] = 0;
|
||||
if ( isset( $pieces['fields'][ $field_name ]['options'] ) ) {
|
||||
$pieces['fields'][ $field_name ]['options']['required'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pieces;
|
||||
}
|
||||
195
inc/pods-save-error-handler.php
Normal file
195
inc/pods-save-error-handler.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
/**
|
||||
* Intercepte les erreurs de validation Pods lors du save d'un post admin :
|
||||
* - Empêche wp_die() (qui publiait quand même le post sans les champs Pods)
|
||||
* - Annule le changement de statut si le post n'était pas encore publié
|
||||
* - Redirige vers la page d'édition avec les champs restaurés via transient
|
||||
*/
|
||||
|
||||
// Capture l'ID du post en cours de sauvegarde (avant Pods, qui peut le créer pour les nouveaux posts)
|
||||
add_action( 'save_post', function ( $post_id ) {
|
||||
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
$GLOBALS['thalim_saving_post_id'] = $post_id;
|
||||
}, 1 );
|
||||
|
||||
// Intercepte wp_die() de Pods pendant un save admin
|
||||
add_filter( 'pods_error_die', function ( $die, $error ) {
|
||||
if ( ! is_admin() || ! isset( $_REQUEST['action'] ) || $_REQUEST['action'] !== 'editpost' ) {
|
||||
return $die;
|
||||
}
|
||||
|
||||
$post_id = $GLOBALS['thalim_saving_post_id'] ?? intval( $_POST['post_ID'] ?? 0 );
|
||||
if ( ! $post_id ) {
|
||||
return $die;
|
||||
}
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
|
||||
// Collecter les valeurs Pods soumises
|
||||
$restore = [];
|
||||
foreach ( $_POST as $key => $val ) {
|
||||
if ( str_starts_with( $key, 'pods_meta_' ) ) {
|
||||
$restore[ $key ] = is_array( $val ) ? array_map( 'wp_unslash', $val ) : wp_unslash( $val );
|
||||
}
|
||||
}
|
||||
$error_text = is_wp_error( $error ) ? $error->get_error_message() : (string) $error;
|
||||
$restore['_msg'] = wp_strip_all_tags( $error_text );
|
||||
$restore['_title'] = sanitize_text_field( wp_unslash( $_POST['post_title'] ?? '' ) );
|
||||
|
||||
set_transient( 'thalim_pods_restore_' . $post_id . '_' . $user_id, $restore, 10 * MINUTE_IN_SECONDS );
|
||||
|
||||
$GLOBALS['thalim_pods_error_post_id'] = $post_id;
|
||||
|
||||
return false; // empêche wp_die()
|
||||
}, 10, 2 );
|
||||
|
||||
// Après le save : rediriger vers la page d'édition + annuler le statut si besoin
|
||||
add_filter( 'redirect_post_location', function ( $location ) {
|
||||
$post_id = $GLOBALS['thalim_pods_error_post_id'] ?? 0;
|
||||
if ( ! $post_id ) {
|
||||
return $location;
|
||||
}
|
||||
|
||||
// Annuler le changement de statut vers publish si le post n'était pas encore publié
|
||||
$original = isset( $_POST['original_post_status'] ) ? sanitize_key( $_POST['original_post_status'] ) : '';
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if (
|
||||
$post &&
|
||||
in_array( $post->post_status, [ 'publish', 'future', 'pending' ], true ) &&
|
||||
! in_array( $original, [ 'publish', 'future', 'pending' ], true )
|
||||
) {
|
||||
global $wpdb;
|
||||
$wpdb->update(
|
||||
$wpdb->posts,
|
||||
[ 'post_status' => $original ?: 'draft' ],
|
||||
[ 'ID' => $post_id ],
|
||||
[ '%s' ],
|
||||
[ '%d' ]
|
||||
);
|
||||
clean_post_cache( $post_id );
|
||||
}
|
||||
|
||||
return admin_url( 'post.php?post=' . $post_id . '&action=edit' );
|
||||
}, 10 );
|
||||
|
||||
// Sur la page d'édition (GET) : lire le transient une seule fois → global → supprimer
|
||||
add_action( 'current_screen', function ( $screen ) {
|
||||
if ( $screen->base !== 'post' ) {
|
||||
return;
|
||||
}
|
||||
$post_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : 0;
|
||||
if ( ! $post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
$key = 'thalim_pods_restore_' . $post_id . '_' . $user_id;
|
||||
$data = get_transient( $key );
|
||||
if ( ! $data ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$GLOBALS['thalim_pods_restore'] = [
|
||||
'post_id' => $post_id,
|
||||
'data' => $data,
|
||||
];
|
||||
delete_transient( $key );
|
||||
} );
|
||||
|
||||
// Injecter les valeurs dans get_post_meta → Pods DFV les embarque dans son JSON React
|
||||
add_filter( 'get_post_metadata', function ( $value, $object_id, $meta_key, $single ) {
|
||||
$restore = $GLOBALS['thalim_pods_restore'] ?? null;
|
||||
if ( ! $restore || $restore['post_id'] !== (int) $object_id ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$pods_key = 'pods_meta_' . $meta_key;
|
||||
if ( ! isset( $restore['data'][ $pods_key ] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$val = $restore['data'][ $pods_key ];
|
||||
return $single ? $val : [ $val ];
|
||||
}, 10, 4 );
|
||||
|
||||
// Restauration JS : titre + champs Pods select/pick via PodsDFV (même pattern que les modales)
|
||||
add_action( 'admin_footer', function () {
|
||||
$restore = $GLOBALS['thalim_pods_restore'] ?? null;
|
||||
if ( ! $restore ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
if ( ! $screen || $screen->base !== 'post' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post_id = intval( $restore['post_id'] );
|
||||
$title = $restore['data']['_title'] ?? '';
|
||||
|
||||
// Construire le map fieldName => value pour les champs Pods
|
||||
$fields = [];
|
||||
foreach ( $restore['data'] as $key => $val ) {
|
||||
if ( str_starts_with( $key, 'pods_meta_' ) ) {
|
||||
$fields[ substr( $key, 10 ) ] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<script>
|
||||
(function ($) {
|
||||
var postId = <?php echo $post_id; ?>;
|
||||
var fields = <?php echo wp_json_encode( $fields ); ?>;
|
||||
var title = <?php echo wp_json_encode( $title ); ?>;
|
||||
|
||||
function doRestore() {
|
||||
// Titre WordPress (non géré par get_post_metadata)
|
||||
var $titleInput = $('#title');
|
||||
if ($titleInput.length && !$titleInput.val() && title) {
|
||||
$titleInput.val(title).trigger('input');
|
||||
}
|
||||
|
||||
// Champs Pods : DOM direct + PodsDFV pour les selects/picks
|
||||
Object.keys(fields).forEach(function (fieldName) {
|
||||
var value = fields[fieldName];
|
||||
var $el = $('[name="pods_meta_' + fieldName + '"]');
|
||||
if ($el.length) {
|
||||
$el.val(value).trigger('change');
|
||||
}
|
||||
if (window.PodsDFV && postId) {
|
||||
try {
|
||||
window.PodsDFV.setFieldValue('post', postId, fieldName, value, 0);
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(window).on('load', function () {
|
||||
setTimeout(doRestore, 300);
|
||||
});
|
||||
}(jQuery));
|
||||
</script>
|
||||
<?php
|
||||
} );
|
||||
|
||||
// Afficher le message d'erreur en admin notice
|
||||
add_action( 'admin_notices', function () {
|
||||
$restore = $GLOBALS['thalim_pods_restore'] ?? null;
|
||||
if ( ! $restore ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
if ( ! $screen || $screen->base !== 'post' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$msg = esc_html( $restore['data']['_msg'] ?? '' );
|
||||
if ( $msg ) {
|
||||
echo '<div class="notice notice-error is-dismissible"><p>' . $msg . '</p></div>';
|
||||
}
|
||||
echo '<div class="notice notice-info is-dismissible"><p>Votre contenu a été restauré. Vérifiez les champs obligatoires avant de republier.</p></div>';
|
||||
} );
|
||||
172
inc/post-card-helpers.php
Normal file
172
inc/post-card-helpers.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Build card display data for a single post.
|
||||
* Resolves Pods relationship fields (stored as multiple meta rows) into
|
||||
* ready-to-display values so Twig templates don't need to call PHP functions.
|
||||
*
|
||||
* Returns an associative array with resolved card fields.
|
||||
*/
|
||||
function thalim_get_card_data($post_id) {
|
||||
$data = [
|
||||
'card_image' => null,
|
||||
'card_membres' => [],
|
||||
'card_axes' => [],
|
||||
'card_etiquettes' => [],
|
||||
'parent_slug' => '',
|
||||
'card_category_name' => '',
|
||||
'card_category_url' => '',
|
||||
'card_type' => '',
|
||||
'card_event_date' => '',
|
||||
'card_event_date_iso' => '',
|
||||
'card_link' => '',
|
||||
];
|
||||
|
||||
// Event date — date_de_debut (events), fallback to datetime (communications)
|
||||
// Used for display instead of post_date when set
|
||||
foreach (['date_de_debut', 'datetime'] as $date_key) {
|
||||
$event_raw = get_post_meta($post_id, $date_key, true) ?: '';
|
||||
if ($event_raw && !str_starts_with($event_raw, '0000-00-00')) {
|
||||
$ts = strtotime($event_raw);
|
||||
if ($ts) {
|
||||
$data['card_event_date'] = date_i18n('d/m/Y', $ts);
|
||||
$data['card_event_date_iso'] = date('Y-m-d', $ts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve top-level parent category slug for color theming and direct category name for display
|
||||
$categories = wp_get_post_categories($post_id, ['fields' => 'all']);
|
||||
$excluded_ids = [12, 31];
|
||||
$is_seance = false;
|
||||
foreach ($categories as $cat) {
|
||||
if ($cat->term_id === 12) { $is_seance = true; }
|
||||
}
|
||||
foreach ($categories as $cat) {
|
||||
if (in_array($cat->term_id, $excluded_ids)) continue;
|
||||
$ancestor_ids = get_ancestors($cat->term_id, 'category');
|
||||
if (!empty($ancestor_ids)) {
|
||||
$root = get_category(end($ancestor_ids));
|
||||
} else {
|
||||
$root = $cat;
|
||||
}
|
||||
$data['parent_slug'] = $root->slug;
|
||||
$data['card_category_name'] = thalim_cat_name($cat);
|
||||
$data['card_category_url'] = get_category_link($cat->term_id);
|
||||
break;
|
||||
}
|
||||
|
||||
// Séances de séminaire: link to parent séminaire with hash, derive color from parent's categories
|
||||
if ($is_seance) {
|
||||
// Always show the category label for séances even though cat 12 is excluded from color resolution
|
||||
if (!$data['card_category_name']) {
|
||||
$seance_cat = get_category(12);
|
||||
if ($seance_cat) {
|
||||
$data['card_category_name'] = thalim_cat_name($seance_cat);
|
||||
$data['card_category_url'] = get_category_link(12);
|
||||
}
|
||||
}
|
||||
global $wpdb;
|
||||
$parent_id = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT pm.post_id FROM {$wpdb->postmeta} pm
|
||||
JOIN {$wpdb->posts} p ON p.ID = pm.post_id
|
||||
WHERE pm.meta_key = 'seances' AND pm.meta_value = %s
|
||||
AND p.post_status = 'publish'
|
||||
LIMIT 1",
|
||||
(string) $post_id
|
||||
));
|
||||
if ($parent_id) {
|
||||
$data['card_link'] = get_permalink((int) $parent_id) . '#seance-' . $post_id;
|
||||
// Derive color from parent séminaire's categories if not already set
|
||||
if (!$data['parent_slug']) {
|
||||
foreach (wp_get_post_categories((int) $parent_id, ['fields' => 'all']) as $cat) {
|
||||
if (in_array($cat->term_id, $excluded_ids)) continue;
|
||||
$ancestor_ids = get_ancestors($cat->term_id, 'category');
|
||||
$root = !empty($ancestor_ids) ? get_category(end($ancestor_ids)) : $cat;
|
||||
$data['parent_slug'] = $root->slug;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Type label (first non-empty type_* field)
|
||||
$type_fields = [
|
||||
'type_colloque_journee_d_etude',
|
||||
'type_soutenance',
|
||||
'type_evenement_culturel',
|
||||
'type_media',
|
||||
'type_captation',
|
||||
'type_revue_collection',
|
||||
'type_autre',
|
||||
];
|
||||
foreach ($type_fields as $field) {
|
||||
$val = get_post_meta($post_id, $field, true);
|
||||
if ($val) {
|
||||
$data['card_type'] = $val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// First image from documents_joints
|
||||
$doc_ids = get_post_meta($post_id, 'documents_joints', false);
|
||||
foreach ($doc_ids as $doc_id) {
|
||||
$mime = get_post_mime_type($doc_id);
|
||||
if ($mime && str_starts_with($mime, 'image/')) {
|
||||
$src = wp_get_attachment_image_url($doc_id, 'medium');
|
||||
if ($src) {
|
||||
$data['card_image'] = $src;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Members (user IDs → display names + profile URLs)
|
||||
// Falls back to autre_membres if membres is empty
|
||||
$membre_ids = get_post_meta($post_id, 'membres', false);
|
||||
if (empty($membre_ids)) {
|
||||
$membre_ids = get_post_meta($post_id, 'autre_membres', false);
|
||||
}
|
||||
foreach ($membre_ids as $uid) {
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$data['card_membres'][] = [
|
||||
'name' => $user->display_name,
|
||||
'url' => get_author_posts_url($uid),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Axes thématiques (post IDs → titles)
|
||||
$axe_ids = get_post_meta($post_id, 'axes_thematiques', false);
|
||||
foreach ($axe_ids as $axe_id) {
|
||||
$axe = get_post($axe_id);
|
||||
if ($axe) {
|
||||
$data['card_axes'][] = $axe->post_title;
|
||||
}
|
||||
}
|
||||
|
||||
// Etiquettes (post IDs → titles)
|
||||
$tag_ids = get_post_meta($post_id, 'etiquettes', false);
|
||||
foreach ($tag_ids as $tag_id) {
|
||||
$tag_post = get_post($tag_id);
|
||||
if ($tag_post) {
|
||||
$data['card_etiquettes'][] = $tag_post->post_title;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build card data map for a collection of posts.
|
||||
* Returns an array keyed by post ID.
|
||||
*/
|
||||
function thalim_get_cards_data($posts) {
|
||||
$cards = [];
|
||||
foreach ($posts as $post) {
|
||||
$cards[$post->ID] = thalim_get_card_data($post->ID);
|
||||
}
|
||||
return $cards;
|
||||
}
|
||||
57
inc/post-title-required.php
Normal file
57
inc/post-title-required.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* Require a non-empty title when saving a post from the admin.
|
||||
*
|
||||
* Uses the same transient / redirect / restore mechanism as pods-save-error-handler.php
|
||||
* so content is never lost: the post saves (with empty title), the status is reverted
|
||||
* to draft if needed, the editor reopens with all fields restored and an error notice.
|
||||
*/
|
||||
add_action( 'save_post', 'thalim_check_post_title_required', 5 );
|
||||
|
||||
function thalim_check_post_title_required( $post_id ) {
|
||||
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
if ( ( $_POST['action'] ?? '' ) !== 'editpost' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post = get_post( $post_id );
|
||||
if ( ! $post || ! post_type_supports( $post->post_type, 'title' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Title was provided — nothing to do.
|
||||
if ( trim( wp_unslash( $_POST['post_title'] ?? '' ) ) !== '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Title is empty: store restore transient and signal the redirect handler
|
||||
// (same keys as pods-save-error-handler.php so everything is shared).
|
||||
$user_id = get_current_user_id();
|
||||
$restore = [];
|
||||
|
||||
foreach ( $_POST as $key => $val ) {
|
||||
if ( str_starts_with( $key, 'pods_meta_' ) ) {
|
||||
$restore[ $key ] = is_array( $val )
|
||||
? array_map( 'wp_unslash', $val )
|
||||
: wp_unslash( $val );
|
||||
}
|
||||
}
|
||||
|
||||
$restore['_msg'] = __( 'Le champ Titre est obligatoire.', 'thalim' );
|
||||
$restore['_title'] = ''; // intentionally empty — user must fill it
|
||||
|
||||
set_transient(
|
||||
'thalim_pods_restore_' . $post_id . '_' . $user_id,
|
||||
$restore,
|
||||
10 * MINUTE_IN_SECONDS
|
||||
);
|
||||
|
||||
// Signal redirect_post_location (defined in pods-save-error-handler.php):
|
||||
// it will revert the post status if needed and redirect to the edit screen.
|
||||
$GLOBALS['thalim_pods_error_post_id'] = $post_id;
|
||||
}
|
||||
447
inc/single-helpers.php
Normal file
447
inc/single-helpers.php
Normal file
@@ -0,0 +1,447 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Format a Pods datetime string (e.g. "2026-01-17 00:00:00") into natural French/English.
|
||||
* Shows time only if not midnight.
|
||||
*/
|
||||
function thalim_format_date($raw, $lang = 'fr') {
|
||||
if (!$raw || str_starts_with($raw, '0000-00-00')) return '';
|
||||
$ts = strtotime($raw);
|
||||
if ($ts === false || $ts < 0) return '';
|
||||
return date_i18n('j F Y', $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve all Pods custom fields for a single post into a display-ready array.
|
||||
*/
|
||||
function thalim_get_single_data($post_id) {
|
||||
$lang = thalim_current_language();
|
||||
|
||||
$data = [
|
||||
// Text fields
|
||||
'sous_titre' => thalim_bilingual( get_post_meta($post_id, 'sous-titre', true) ?: '', $lang ),
|
||||
'reference_bibliographique' => get_post_meta($post_id, 'reference_bibliographique', true) ?: '',
|
||||
'editeur' => get_post_meta($post_id, 'editeur', true) ?: '',
|
||||
'journal' => get_post_meta($post_id, 'journal', true) ?: '',
|
||||
'lieu' => thalim_bilingual( get_post_meta($post_id, 'lieu', true) ?: '', $lang ),
|
||||
'adresse' => get_post_meta($post_id, 'adresse', true) ?: '',
|
||||
'autrepersonnes' => get_post_meta($post_id, 'autrepersonnes', true) ?: '',
|
||||
'autre_autrepersonnes' => get_post_meta($post_id, 'autre_autrepersonnes', true) ?: '',
|
||||
'body_en' => apply_filters( 'the_content', get_post_meta($post_id, 'body_en', true) ?: '' ),
|
||||
|
||||
// Dates (formatted for display)
|
||||
'datetime' => thalim_format_date(get_post_meta($post_id, 'datetime', true), $lang),
|
||||
'date_de_debut' => '',
|
||||
'date_de_fin' => '',
|
||||
'date_debut_ymd' => '',
|
||||
'date_fin_ymd' => '',
|
||||
'heure_de_debut' => substr( get_post_meta($post_id, 'heure_de_debut', true) ?: '', 0, 5 ),
|
||||
'heure_de_fin' => substr( get_post_meta($post_id, 'heure_de_fin', true) ?: '', 0, 5 ),
|
||||
|
||||
// URLs
|
||||
'hal_url' => get_post_meta($post_id, 'hal_url', true) ?: '',
|
||||
'hal_file' => get_post_meta($post_id, 'hal_file', true) ?: '',
|
||||
'canal_u' => array_values( array_filter( array_map( function( $url ) {
|
||||
if ( preg_match( '/(\d+)\/?$/', trim( $url ), $m ) ) {
|
||||
return 'https://www.canal-u.tv/embed/' . $m[1] . '?t=0';
|
||||
}
|
||||
return '';
|
||||
}, get_post_meta( $post_id, 'lien_canal_u', false ) ) ) ),
|
||||
'youtube' => array_values( array_filter( array_map( function( $url ) {
|
||||
$url = trim( $url );
|
||||
// youtu.be/ID or youtube.com/embed/ID or youtube.com/watch?v=ID
|
||||
if ( preg_match( '/(?:youtu\.be\/|youtube\.com\/(?:embed\/|watch\?.*v=|shorts\/))([A-Za-z0-9_-]{11})/', $url, $m ) ) {
|
||||
return 'https://www.youtube-nocookie.com/embed/' . $m[1];
|
||||
}
|
||||
return '';
|
||||
}, get_post_meta( $post_id, 'lien_youtube', false ) ) ) ),
|
||||
|
||||
// Resolved below
|
||||
'liens_externes' => [],
|
||||
'membres' => [],
|
||||
'autre_membres' => [],
|
||||
'autre_fonction_label' => '',
|
||||
'axes' => [],
|
||||
'etiquettes' => [],
|
||||
'programmes' => [],
|
||||
'annonces_liees' => [],
|
||||
'seances_a_venir' => [],
|
||||
'seances_passees' => [],
|
||||
'show_image_titles' => (bool) get_post_meta($post_id, 'afficher_le_titre_des_images_en_legende', true),
|
||||
'images' => [],
|
||||
'documents' => [],
|
||||
'type_label' => '',
|
||||
'fonction_label' => '',
|
||||
'parent_slug' => '',
|
||||
'parent_name' => '',
|
||||
'parent_link' => '',
|
||||
'category_name' => '',
|
||||
'category_link' => '',
|
||||
];
|
||||
|
||||
// --- Dates ---
|
||||
$raw_debut = get_post_meta($post_id, 'date_de_debut', true);
|
||||
$raw_fin = get_post_meta($post_id, 'date_de_fin', true);
|
||||
$ts_debut = ($raw_debut && !str_starts_with($raw_debut, '0000-00-00')) ? strtotime($raw_debut) : 0;
|
||||
$ts_fin = ($raw_fin && !str_starts_with($raw_fin, '0000-00-00')) ? strtotime($raw_fin) : 0;
|
||||
|
||||
$data['date_de_debut'] = thalim_format_date($raw_debut, $lang);
|
||||
$data['date_de_fin'] = thalim_format_date($raw_fin, $lang);
|
||||
if ($ts_debut) $data['date_debut_ymd'] = date('Y-m-d', $ts_debut);
|
||||
if ($ts_fin) $data['date_fin_ymd'] = date('Y-m-d', $ts_fin);
|
||||
|
||||
// --- External links (up to 3) ---
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$url = get_post_meta($post_id, 'lien_externe_' . $i, true);
|
||||
if ($url) {
|
||||
$titre = thalim_bilingual( get_post_meta($post_id, 'titre_du_lien_externe_' . $i, true) ?: '', $lang );
|
||||
if (!$titre) {
|
||||
$host = parse_url($url, PHP_URL_HOST) ?: $url;
|
||||
$parts = explode('.', $host);
|
||||
$titre = count($parts) >= 2 ? implode('.', array_slice($parts, -2)) : $host;
|
||||
}
|
||||
$data['liens_externes'][] = [
|
||||
'url' => $url,
|
||||
'titre' => $titre,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Category hierarchy for breadcrumb and color ---
|
||||
$categories = wp_get_post_categories($post_id, ['fields' => 'all']);
|
||||
$excluded_ids = [12, 31];
|
||||
foreach ($categories as $cat) {
|
||||
if (in_array($cat->term_id, $excluded_ids)) continue;
|
||||
$ancestor_ids = get_ancestors($cat->term_id, 'category');
|
||||
if (!empty($ancestor_ids)) {
|
||||
$root = get_category(end($ancestor_ids));
|
||||
$data['parent_slug'] = $root->slug;
|
||||
$data['parent_name'] = $root->name;
|
||||
$data['parent_link'] = get_category_link($root->term_id);
|
||||
$data['category_name'] = $cat->name;
|
||||
} else {
|
||||
$data['parent_slug'] = $cat->slug;
|
||||
$data['parent_name'] = $cat->name;
|
||||
$data['parent_link'] = get_category_link($cat->term_id);
|
||||
$data['category_name'] = $lang === 'en' ? 'Other' : 'Autre';
|
||||
}
|
||||
// category_link: for direct posts (no ancestors), point to the /autres index
|
||||
$data['category_link'] = empty($ancestor_ids)
|
||||
? trailingslashit(get_category_link($cat->term_id)) . 'autres/'
|
||||
: get_category_link($cat->term_id);
|
||||
break;
|
||||
}
|
||||
|
||||
// --- Documents joints: split images vs files ---
|
||||
$doc_ids = get_post_meta($post_id, 'documents_joints', false);
|
||||
foreach ($doc_ids as $doc_id) {
|
||||
$mime = get_post_mime_type($doc_id);
|
||||
if (!$mime) continue;
|
||||
if (str_starts_with($mime, 'image/')) {
|
||||
$src = wp_get_attachment_image_url($doc_id, 'large');
|
||||
if ($src) {
|
||||
$meta = wp_get_attachment_metadata($doc_id);
|
||||
$w = isset($meta['width']) ? $meta['width'] : 0;
|
||||
$h = isset($meta['height']) ? $meta['height'] : 0;
|
||||
$data['images'][] = [
|
||||
'url' => $src,
|
||||
'alt' => get_post_meta($doc_id, '_wp_attachment_image_alt', true) ?: '',
|
||||
'caption' => thalim_bilingual(wp_get_attachment_caption($doc_id) ?: '', $lang),
|
||||
'title' => thalim_bilingual(get_the_title($doc_id) ?: '', $lang),
|
||||
'portrait' => ($h > $w),
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$data['documents'][] = [
|
||||
'url' => wp_get_attachment_url($doc_id),
|
||||
'title' => thalim_bilingual(get_the_title($doc_id) ?: '', $lang) ?: basename(get_attached_file($doc_id)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Members (user IDs → name + profile URL) ---
|
||||
foreach (get_post_meta($post_id, 'membres', false) as $uid) {
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$data['membres'][] = [
|
||||
'name' => $user->display_name,
|
||||
'url' => get_author_posts_url($uid),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Autre membres (user IDs → name + profile URL) ---
|
||||
foreach (get_post_meta($post_id, 'autre_membres', false) as $uid) {
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$data['autre_membres'][] = [
|
||||
'name' => $user->display_name,
|
||||
'url' => get_author_posts_url($uid),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Axes thématiques (taxonomy term IDs) ---
|
||||
$axe_ids = get_post_meta($post_id, 'axes_thematiques', false);
|
||||
foreach ($axe_ids as $axe_id) {
|
||||
$term = get_term(intval($axe_id), 'axe_thematique');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$data['axes'][] = [
|
||||
'id' => $term->term_id,
|
||||
'name' => thalim_bilingual($term->name, $lang),
|
||||
'url' => get_term_link($term),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Étiquettes (taxonomy term IDs) ---
|
||||
$tag_ids = get_post_meta($post_id, 'etiquettes', false);
|
||||
foreach ($tag_ids as $tag_id) {
|
||||
$term = get_term(intval($tag_id), 'post_tag');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$data['etiquettes'][] = [
|
||||
'id' => $term->term_id,
|
||||
'name' => thalim_bilingual($term->name, $lang),
|
||||
'url' => get_term_link($term),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Programmes de recherche (taxonomy term IDs) ---
|
||||
$prog_ids = get_post_meta($post_id, 'programmes_de_recherche', false);
|
||||
foreach ($prog_ids as $prog_id) {
|
||||
$term = get_term(intval($prog_id), 'programme_de_recherche');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$data['programmes'][] = [
|
||||
'id' => $term->term_id,
|
||||
'name' => thalim_bilingual($term->name, $lang),
|
||||
'url' => get_term_link($term),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// --- Annonces liées (related posts) ---
|
||||
$related_ids = get_post_meta($post_id, 'annonces_liees', false);
|
||||
if (!empty($related_ids)) {
|
||||
$data['annonces_liees'] = Timber::get_posts([
|
||||
'post_type' => 'post',
|
||||
'post__in' => array_map('intval', $related_ids),
|
||||
'posts_per_page' => -1,
|
||||
'lang' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
// --- Séances (session posts) — split into upcoming / past ---
|
||||
$seance_ids = get_post_meta($post_id, 'seances', false);
|
||||
$data['seances_a_venir'] = [];
|
||||
$data['seances_passees'] = [];
|
||||
if (!empty($seance_ids)) {
|
||||
$seance_posts = Timber::get_posts([
|
||||
'post_type' => 'post',
|
||||
'post__in' => array_map('intval', $seance_ids),
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'meta_value',
|
||||
'meta_key' => 'date_de_debut',
|
||||
'order' => 'ASC',
|
||||
'lang' => '',
|
||||
'post_status' => ['publish', 'future'],
|
||||
]);
|
||||
$now = time();
|
||||
$current_year = date('Y');
|
||||
$months_fr = ['jan.', 'fév.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'];
|
||||
$months_en = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.'];
|
||||
|
||||
foreach ($seance_posts as $seance) {
|
||||
$raw_date = get_post_meta($seance->ID, 'date_de_debut', true);
|
||||
$ts = $raw_date ? strtotime($raw_date) : strtotime($seance->post_date);
|
||||
|
||||
// Only expose date_fin when it's a different day than date_de_debut
|
||||
$raw_fin = get_post_meta($seance->ID, 'date_de_fin', true);
|
||||
$ts_fin = $raw_fin && !str_starts_with($raw_fin, '0000-00-00') ? strtotime($raw_fin) : false;
|
||||
$date_fin_display = ($ts_fin && date('Y-m-d', $ts_fin) !== date('Y-m-d', $ts))
|
||||
? thalim_format_date($raw_fin, $lang)
|
||||
: '';
|
||||
|
||||
$month_idx = intval(date('n', $ts)) - 1;
|
||||
$seance_data = [
|
||||
'post' => $seance,
|
||||
'day' => date('d', $ts),
|
||||
'month' => ($lang === 'en') ? $months_en[$month_idx] : $months_fr[$month_idx],
|
||||
'year' => (date('Y', $ts) !== $current_year) ? date('Y', $ts) : '',
|
||||
'date_full' => thalim_format_date($raw_date, $lang),
|
||||
'date_fin' => $date_fin_display,
|
||||
'heure_de_debut' => substr( get_post_meta($seance->ID, 'heure_de_debut', true) ?: '', 0, 5 ),
|
||||
'heure_de_fin' => substr( get_post_meta($seance->ID, 'heure_de_fin', true) ?: '', 0, 5 ),
|
||||
'lieu' => thalim_bilingual( get_post_meta($seance->ID, 'lieu', true) ?: '', $lang ),
|
||||
'adresse' => get_post_meta($seance->ID, 'adresse', true) ?: '',
|
||||
'body_en' => apply_filters( 'the_content', get_post_meta($seance->ID, 'body_en', true) ?: '' ),
|
||||
'intervenants' => [],
|
||||
'images' => [],
|
||||
'documents' => [],
|
||||
'liens_externes' => [],
|
||||
'annonces_liees' => [],
|
||||
];
|
||||
|
||||
// Resolve intervenants (membres or autrepersonnes)
|
||||
$m_ids = get_post_meta($seance->ID, 'membres', false);
|
||||
if (empty($m_ids)) {
|
||||
$m_ids = get_post_meta($seance->ID, 'autre_membres', false);
|
||||
}
|
||||
foreach ($m_ids as $uid) {
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$seance_data['intervenants'][] = [
|
||||
'name' => $user->display_name,
|
||||
'url' => get_author_posts_url($uid),
|
||||
];
|
||||
}
|
||||
}
|
||||
$seance_data['autrepersonnes'] = get_post_meta($seance->ID, 'autrepersonnes', true) ?: '';
|
||||
$seance_data['show_image_titles'] = (bool) get_post_meta($seance->ID, 'afficher_le_titre_des_images_en_legende', true);
|
||||
|
||||
// Documents joints: images and files
|
||||
$s_doc_ids = get_post_meta($seance->ID, 'documents_joints', false);
|
||||
foreach ($s_doc_ids as $doc_id) {
|
||||
$mime = get_post_mime_type($doc_id);
|
||||
if (!$mime) continue;
|
||||
if (str_starts_with($mime, 'image/')) {
|
||||
$src = wp_get_attachment_image_url($doc_id, 'large');
|
||||
if ($src) {
|
||||
$seance_data['images'][] = [
|
||||
'url' => $src,
|
||||
'alt' => get_post_meta($doc_id, '_wp_attachment_image_alt', true) ?: '',
|
||||
'caption' => thalim_bilingual(wp_get_attachment_caption($doc_id) ?: '', $lang),
|
||||
'title' => thalim_bilingual(get_the_title($doc_id) ?: '', $lang),
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$seance_data['documents'][] = [
|
||||
'url' => wp_get_attachment_url($doc_id),
|
||||
'title' => thalim_bilingual(get_the_title($doc_id) ?: '', $lang) ?: basename(get_attached_file($doc_id)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// External links (up to 3)
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$url = get_post_meta($seance->ID, 'lien_externe_' . $i, true);
|
||||
if ($url) {
|
||||
$titre = thalim_bilingual( get_post_meta($seance->ID, 'titre_du_lien_externe_' . $i, true) ?: '', $lang );
|
||||
if (!$titre) {
|
||||
$host = parse_url($url, PHP_URL_HOST) ?: $url;
|
||||
$parts = explode('.', $host);
|
||||
$titre = count($parts) >= 2 ? implode('.', array_slice($parts, -2)) : $host;
|
||||
}
|
||||
$seance_data['liens_externes'][] = ['url' => $url, 'titre' => $titre];
|
||||
}
|
||||
}
|
||||
|
||||
// Annonces liées
|
||||
$s_related_ids = get_post_meta($seance->ID, 'annonces_liees', false);
|
||||
if (!empty($s_related_ids)) {
|
||||
$seance_data['annonces_liees'] = Timber::get_posts([
|
||||
'post_type' => 'post',
|
||||
'post__in' => array_map('intval', $s_related_ids),
|
||||
'posts_per_page' => -1,
|
||||
'lang' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($ts >= $now) {
|
||||
$data['seances_a_venir'][] = $seance_data;
|
||||
} else {
|
||||
$data['seances_passees'][] = $seance_data;
|
||||
}
|
||||
}
|
||||
// Past séances: most recent first
|
||||
$data['seances_passees'] = array_reverse($data['seances_passees']);
|
||||
}
|
||||
|
||||
// --- Type label (category-conditional type fields) ---
|
||||
$type_fields = [
|
||||
'type_colloque_journee_d_etude',
|
||||
'type_soutenance',
|
||||
'type_evenement_culturel',
|
||||
'type_media',
|
||||
'type_captation',
|
||||
'type_revue_collection',
|
||||
'type_autre',
|
||||
];
|
||||
foreach ($type_fields as $field) {
|
||||
$val = get_post_meta($post_id, $field, true);
|
||||
if ($val) {
|
||||
$data['type_label'] = thalim_bilingual( $val, $lang );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Fonction label (first non-empty fonction_* field) ---
|
||||
$fonction_fields = [
|
||||
'fonction_auteur',
|
||||
'fonction_organisation',
|
||||
'fonction_intervention',
|
||||
'fonction_redaction',
|
||||
'fonction_realisation',
|
||||
'fonction_dirige',
|
||||
'fonction_responsable',
|
||||
'fonction_candidat',
|
||||
];
|
||||
foreach ($fonction_fields as $field) {
|
||||
$val = get_post_meta($post_id, $field, true);
|
||||
if ($val) {
|
||||
$data['fonction_label'] = thalim_bilingual( $val, $lang );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Autre fonction label (first non-empty autre_fonction_* field) ---
|
||||
$autre_fonction_fields = [
|
||||
'autre_fonction_autre',
|
||||
'autre_fonction_concerne',
|
||||
'autre_fonction_directeur',
|
||||
'autre_fonction_direction_d_ouvrage',
|
||||
'autre_fonction_intervenant',
|
||||
'autre_fonction_participants',
|
||||
];
|
||||
foreach ($autre_fonction_fields as $field) {
|
||||
$val = get_post_meta($post_id, $field, true);
|
||||
if ($val) {
|
||||
$data['autre_fonction_label'] = thalim_bilingual( $val, $lang );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Fallback: derive labels from Pods categorie ID for older posts ---
|
||||
if (!$data['fonction_label'] || !$data['autre_fonction_label']) {
|
||||
$pods_cat = get_post_meta($post_id, '_pods_categorie', true);
|
||||
$cat_id = (is_array($pods_cat) && !empty($pods_cat)) ? intval($pods_cat[0]) : 0;
|
||||
|
||||
// Pods categorie ID → fonction label (main membres)
|
||||
$cat_to_fonction = [
|
||||
3 => 'Organisation', 4 => 'Auteur', 6 => 'Responsable',
|
||||
8 => 'Organisation', 9 => 'Responsable', 10 => 'Organisation',
|
||||
11 => 'Organisation', 12 => 'Intervention', 13 => 'Intervention',
|
||||
14 => 'Candidat', 15 => 'Auteur', 16 => 'Auteur',
|
||||
17 => 'Responsable', 18 => 'Organisation', 19 => 'Intervention',
|
||||
21 => 'Rédaction', 22 => 'Réalisation', 23 => 'Intervention',
|
||||
24 => 'Responsable', 25 => 'Responsable', 65 => 'Dirigé par',
|
||||
];
|
||||
|
||||
// Pods categorie ID → autre_fonction label (autre membres)
|
||||
$cat_to_autre_fonction = [
|
||||
3 => 'Participants', 4 => "Direction d'ouvrage",
|
||||
10 => 'Participants', 14 => 'Directeur de thèse',
|
||||
15 => "Direction d'ouvrage", 16 => "Direction d'ouvrage",
|
||||
19 => 'Membre concerné', 22 => 'Intervenant',
|
||||
];
|
||||
|
||||
if (!$data['fonction_label'] && isset($cat_to_fonction[$cat_id])) {
|
||||
$data['fonction_label'] = $cat_to_fonction[$cat_id];
|
||||
}
|
||||
if (!$data['autre_fonction_label'] && isset($cat_to_autre_fonction[$cat_id])) {
|
||||
$data['autre_fonction_label'] = $cat_to_autre_fonction[$cat_id];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
Reference in New Issue
Block a user