correction doublons index Ajax + découplage slug categories couleurs

This commit is contained in:
2026-06-04 17:41:11 +02:00
parent d900e7aa65
commit bea33f9fd3
5 changed files with 92 additions and 36 deletions

View File

@@ -125,6 +125,24 @@ function thalim_cat_name( $cat, string $lang = null ): string {
return ( $en !== '' && $en !== false ) ? $en : $fallback;
}
/**
* Clé couleur stable d'une catégorie racine, indexée sur le term_id (immuable)
* plutôt que sur le slug (que l'admin peut régénérer en renommant la catégorie).
* Renvoie la clé canonique attendue par les classes CSS .gradient--{clé} /
* .category--{clé} (_postcard.scss, _single.scss, _category.scss).
* Fallback sur le slug live pour toute racine hors des 5 rubriques connues.
*/
function thalim_category_color_slug( $root_term_id, $fallback_slug = '' ) {
$map = [
1 => 'le-laboratoire',
3 => 'manifestations-scientifiques',
4 => 'publications-et-productions',
5 => 'mediation-scientifique',
6 => 'ressources',
];
return $map[ (int) $root_term_id ] ?? $fallback_slug;
}
// Register bilingual and en_url as Twig filters
add_filter( 'timber/twig', function ( $twig ) {
$twig->addFilter( new \Twig\TwigFilter( 'bilingual', 'thalim_bilingual' ) );
@@ -910,6 +928,41 @@ add_filter( 'login_redirect', function( $redirect_to, $requested, $user ) {
return $redirect_to;
}, 10, 3 );
// Return the IDs of posts currently pinned ("épinglé dans la catégorie") in a given category.
// A pin is active if epingler_dans_la_categorie == 1 AND date_de_fin_depinglage is empty/0000-00-00/future.
// Shared by category.php (pull them out of the main flow) and the AJAX handler (exclude them from
// pagination) so both sides stay in sync — a mismatch shifts the page boundary and dupes posts.
function thalim_get_active_pinned_ids( $category_id ) {
if ( ! $category_id ) return [];
$today = date( 'Y-m-d' );
$pinned_query = new WP_Query([
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
'no_found_rows' => true,
'lang' => '',
'tax_query' => [[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => [ $category_id ],
'include_children' => false,
]],
'meta_query' => [[
'key' => 'epingler_dans_la_categorie',
'value' => '1',
]],
]);
$pinned_ids = [];
foreach ( $pinned_query->posts as $pid ) {
$fin = get_post_meta( $pid, 'date_de_fin_depinglage', true );
if ( empty( $fin ) || $fin === '0000-00-00' || $fin >= $today ) {
$pinned_ids[] = $pid;
}
}
return $pinned_ids;
}
// AJAX handler for infinite scroll on category pages
function thalim_load_more_posts() {
check_ajax_referer('load_more_posts', 'nonce');
@@ -930,6 +983,7 @@ function thalim_load_more_posts() {
$query_args = [
'post_type' => 'post',
'post_status' => 'publish', // admin-ajax => is_admin() true: sans ça WP ajoute future/draft/pending et décale la pagination vs le front
'posts_per_page' => 12,
'paged' => $page,
'orderby' => 'date',
@@ -1005,33 +1059,10 @@ function thalim_load_more_posts() {
$query_args['thalim_event_date_filter'] = ['from' => $date_from, 'to' => $date_to];
}
// Exclude pinned posts on category pages to avoid duplicates (they already appear at the top)
// Exclude pinned posts on category pages to avoid duplicates (they already appear at the top,
// pulled out of the main flow by category.php). Must mirror category.php exactly.
if ($category) {
$today = date( 'Y-m-d' );
$pinned_query = new WP_Query([
'post_type' => 'post',
'posts_per_page' => -1,
'fields' => 'ids',
'no_found_rows' => true,
'lang' => '',
'tax_query' => [[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => [$category],
'include_children' => false,
]],
'meta_query' => [[
'key' => 'epingler_dans_la_categorie',
'value' => '1',
]],
]);
$pinned_ids = [];
foreach ( $pinned_query->posts as $pid ) {
$fin = get_post_meta( $pid, 'date_de_fin_depinglage', true );
if ( empty( $fin ) || $fin === '0000-00-00' || $fin >= $today ) {
$pinned_ids[] = $pid;
}
}
$pinned_ids = thalim_get_active_pinned_ids( $category );
if ( ! empty( $pinned_ids ) ) {
$query_args['post__not_in'] = $pinned_ids;
}
@@ -1192,6 +1223,7 @@ function thalim_load_more_agenda() {
$query_args = [
'post_type' => 'post',
'post_status' => 'publish', // admin-ajax => is_admin() true: sans ça WP ajoute future/draft/pending et décale la pagination vs le front
'posts_per_page' => 12,
'paged' => $page,
'orderby' => 'date',
@@ -1292,7 +1324,7 @@ add_filter('posts_orderby', function ($orderby, $query) {
. " WHEN thalim_ed.meta_value " . sprintf($valid, 'thalim_ed.meta_value', 'thalim_ed.meta_value') . " THEN thalim_ed.meta_value"
. " WHEN thalim_dt.meta_value " . sprintf($valid, 'thalim_dt.meta_value', 'thalim_dt.meta_value') . " THEN thalim_dt.meta_value"
. " ELSE {$wpdb->posts}.post_date"
. " END DESC";
. " END DESC, {$wpdb->posts}.ID DESC"; // tiebreaker déterministe: sans lui, les dates ex-æquo paginent de façon instable entre les requêtes séparées (initial vs AJAX)
}, 10, 2);
// Event date range filter: uses same CASE logic as ordering so date_de_debut/datetime take priority over post_date.