From bea33f9fd397f074c5885d34d5aca44e02dce48c Mon Sep 17 00:00:00 2001 From: Valentin Le Moign Date: Thu, 4 Jun 2026 17:41:11 +0200 Subject: [PATCH] =?UTF-8?q?correction=20doublons=20index=20Ajax=20+=20d?= =?UTF-8?q?=C3=A9couplage=20slug=20categories=20couleurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- category.php | 31 +++++++++++--- functions.php | 86 +++++++++++++++++++++++++++------------ inc/post-card-helpers.php | 4 +- inc/single-helpers.php | 4 +- templates/category.twig | 3 ++ 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/category.php b/category.php index 152c61d..1a066b5 100644 --- a/category.php +++ b/category.php @@ -10,10 +10,10 @@ if ( ! is_user_logged_in() ) $excluded_ids[] = 9; // Vie du labo // Parent category slug for color theming if ($category->parent) { $parent_cat = get_category($category->parent); - $context['parent_slug'] = $parent_cat->slug; + $context['parent_slug'] = thalim_category_color_slug($parent_cat->term_id, $parent_cat->slug); $context['active_rubrique'] = $parent_cat->term_id; } else { - $context['parent_slug'] = $category->slug; + $context['parent_slug'] = thalim_category_color_slug($category->term_id, $category->slug); $context['active_rubrique'] = $category->term_id; } @@ -227,6 +227,12 @@ if (!$is_direct && !empty($children)) { } else { $context['is_parent'] = false; $context['is_direct'] = $is_direct; + + // Épinglés sortis du flux principal (et exclus de la pagination AJAX par thalim_load_more_posts), + // affichés dans un bloc dédié en tête. Garde l'initial et l'AJAX sur le même univers : sinon la + // fenêtre de pagination se décale et le post de la couture est dupliqué. + $pinned_ids = thalim_get_active_pinned_ids( $category->term_id ); + $query_args = array_merge([ 'post_type' => 'post', 'tax_query' => [[ @@ -241,9 +247,24 @@ if (!$is_direct && !empty($children)) { 'lang' => '', 'thalim_event_date_order' => true, ], $extra_query_args); - $posts = $sort_with_pinned( Timber::get_posts($query_args) ); - $context['cards'] = thalim_get_cards_data($posts); - $context['posts'] = $posts; + if ( $pinned_ids ) { + $query_args['post__not_in'] = $pinned_ids; + } + $posts = Timber::get_posts($query_args); + + // Pinned posts, respecting the active axe/date filters (so a pin outside the filter doesn't show). + $pinned_posts = $pinned_ids ? Timber::get_posts( array_merge([ + 'post_type' => 'post', + 'post_status' => 'publish', + 'post__in' => $pinned_ids, + 'orderby' => 'post__in', + 'posts_per_page' => -1, + 'lang' => '', + ], $extra_query_args ) ) : []; + + $context['cards'] = thalim_get_cards_data($pinned_posts) + thalim_get_cards_data($posts); + $context['pinned_posts'] = $pinned_posts; + $context['posts'] = $posts; } // View mode toggle (?view=agenda) diff --git a/functions.php b/functions.php index 9299b91..4b39134 100755 --- a/functions.php +++ b/functions.php @@ -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. diff --git a/inc/post-card-helpers.php b/inc/post-card-helpers.php index a3c9235..b858ed7 100644 --- a/inc/post-card-helpers.php +++ b/inc/post-card-helpers.php @@ -99,7 +99,7 @@ function thalim_get_card_data($post_id) { } else { $root = $cat; } - $data['parent_slug'] = $root->slug; + $data['parent_slug'] = thalim_category_color_slug($root->term_id, $root->slug); $data['card_category_name'] = thalim_cat_name($cat); $data['card_category_url'] = get_category_link($cat->term_id); break; @@ -132,7 +132,7 @@ function thalim_get_card_data($post_id) { 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; + $data['parent_slug'] = thalim_category_color_slug($root->term_id, $root->slug); break; } } diff --git a/inc/single-helpers.php b/inc/single-helpers.php index 821d0b4..0695a07 100644 --- a/inc/single-helpers.php +++ b/inc/single-helpers.php @@ -144,12 +144,12 @@ function thalim_get_single_data($post_id) { $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_slug'] = thalim_category_color_slug($root->term_id, $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_slug'] = thalim_category_color_slug($cat->term_id, $cat->slug); $data['parent_name'] = $cat->name; $data['parent_link'] = get_category_link($cat->term_id); $data['category_name'] = $lang === 'en' ? 'Other' : 'Autre'; diff --git a/templates/category.twig b/templates/category.twig index f12510b..e5b0fe0 100644 --- a/templates/category.twig +++ b/templates/category.twig @@ -85,6 +85,9 @@ {% else %}
+ {% for post in pinned_posts %} + {% include 'partials/post-card.twig' with { post: post, card: cards[post.ID], show_category: true, type_only: true } %} + {% endfor %} {% for post in posts %} {% include 'partials/post-card.twig' with { post: post, card: cards[post.ID], show_category: true, type_only: true } %} {% endfor %}