true * 'thalim_event_date_filter' => ['from' => 'Y-m-d', 'to' => 'Y-m-d'] */ // Event date ordering: COALESCE(date_de_debut, datetime, post_date) // Activated by adding 'thalim_event_date_order' => true to WP_Query args. add_filter('posts_join', function ($join, $query) { if (!$query->get('thalim_event_date_order') && !$query->get('thalim_event_date_filter')) return $join; global $wpdb; $join .= " LEFT JOIN {$wpdb->postmeta} AS thalim_ed" . " ON (thalim_ed.post_id = {$wpdb->posts}.ID" . " AND thalim_ed.meta_key = 'date_de_debut') "; $join .= " LEFT JOIN {$wpdb->postmeta} AS thalim_dt" . " ON (thalim_dt.post_id = {$wpdb->posts}.ID" . " AND thalim_dt.meta_key = 'datetime') "; return $join; }, 10, 2); add_filter('posts_orderby', function ($orderby, $query) { if (!$query->get('thalim_event_date_order')) return $orderby; global $wpdb; $valid = "IS NOT NULL AND %s != '' AND %s NOT LIKE '0000-00-00%%'"; return "CASE" . " 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, {$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. // Activated by adding 'thalim_event_date_filter' => ['from' => $date_from, 'to' => $date_to] to WP_Query args. add_filter('posts_where', function ($where, $query) { $filter = $query->get('thalim_event_date_filter'); if (empty($filter) || (!isset($filter['from']) && !isset($filter['to']))) return $where; global $wpdb; $effective = "CASE" . " WHEN thalim_ed.meta_value IS NOT NULL AND thalim_ed.meta_value != '' AND thalim_ed.meta_value NOT LIKE '0000-00-00%' THEN thalim_ed.meta_value" . " WHEN thalim_dt.meta_value IS NOT NULL AND thalim_dt.meta_value != '' AND thalim_dt.meta_value NOT LIKE '0000-00-00%' THEN thalim_dt.meta_value" . " ELSE {$wpdb->posts}.post_date" . " END"; if (!empty($filter['from'])) { $from = $wpdb->prepare('%s', $filter['from']); $where .= " AND ({$effective}) >= {$from}"; } if (!empty($filter['to'])) { $to = $wpdb->prepare('%s', $filter['to'] . ' 23:59:59'); $where .= " AND ({$effective}) <= {$to}"; } return $where; }, 10, 2); // 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, '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; } // ── Axes thématiques groupés pour les filtres ────────────────── // Retourne un tableau de groupes triés par période (plus récent en premier, // "passés" toujours en dernier). Chaque terme contient id, name, ordre. function thalim_get_axes_filter_groups() { $terms = get_terms( [ 'taxonomy' => 'axe_thematique', 'hide_empty' => false ] ); $axes_map = []; foreach ( $terms as $term ) { $debut = trim( get_term_meta( $term->term_id, 'annee_debut', true ) ); $fin = trim( get_term_meta( $term->term_id, 'annee_fin', true ) ); if ( $debut && $fin ) { $key = $debut . '-' . $fin; $label = $debut . ' – ' . $fin; } else { $key = 'passes'; $label = 'Axes antérieurs'; } if ( ! isset( $axes_map[ $key ] ) ) { $axes_map[ $key ] = [ 'label' => $label, 'debut' => intval( $debut ), 'terms' => [] ]; } $ordre = trim( get_term_meta( $term->term_id, 'ordre_daffichage', true ) ); $axes_map[ $key ]['terms'][] = [ 'id' => $term->term_id, 'name' => $term->name, 'ordre' => $ordre !== '' ? intval( $ordre ) : null, 'href' => get_term_link( $term ), ]; } // Tri des groupes : plus récent en premier, passés toujours en dernier uasort( $axes_map, function ( $a, $b ) { if ( $a['label'] === 'Axes antérieurs' ) return 1; if ( $b['label'] === 'Axes antérieurs' ) return -1; return $b['debut'] - $a['debut']; } ); // Tri des termes dans chaque groupe : ordre_daffichage d'abord, puis alphabétique foreach ( $axes_map as &$group ) { usort( $group['terms'], function ( $a, $b ) { $a_has = $a['ordre'] !== null; $b_has = $b['ordre'] !== null; if ( $a_has && $b_has ) return $a['ordre'] - $b['ordre']; if ( $a_has ) return -1; if ( $b_has ) return 1; return strcmp( $a['name'], $b['name'] ); } ); } unset( $group ); return array_values( $axes_map ); }