category_name=$1&name=$2&page=$3 * * Le dernier groupe est un numéro de page (pagination interne d'un article via * ). Un slug purement numérique est donc avalé comme numéro de * page : l'article devient irroutable et répond 404, alors qu'il continue de * s'afficher dans toutes les listes. * * Deux chemins produisent un tel slug : * - un titre vide au moment de la première publication — le cœur retombe alors * sur l'ID du post (wp-includes/post.php, wp_insert_post : sanitize_title( * $post_title, $post_id)) et ne régénère plus jamais le slug ensuite ; * - un titre légitimement numérique (« 1917 »). * * Ce module traite le second cas à la source ; le premier est traité en amont * dans inc/pods-save-error-handler.php (le slug figé est vidé au moment où le * statut est annulé, pour qu'il se régénère depuis le vrai titre). * * Portée volontairement limitée à post/page : les nav_menu_item et les * attachments ont légitimement des slugs numériques et ne passent pas par * cette règle de réécriture. */ /** * Un slug purement numérique est-il à corriger pour ce type de contenu ? * Fonction pure (testable) : la requête d'unicité vit dans le filtre. */ function thalim_slug_needs_guard( string $slug, string $post_type ): bool { if ( ! in_array( $post_type, [ 'post', 'page' ], true ) ) { return false; } return $slug !== '' && ctype_digit( $slug ); } /** * Suffixe les slugs purement numériques (-2, -3, …), en suivant la convention * du cœur pour les slugs en conflit. */ add_filter( 'wp_unique_post_slug', function ( $slug, $post_id, $post_status, $post_type ) { $slug = (string) $slug; if ( ! thalim_slug_needs_guard( $slug, (string) $post_type ) ) { return $slug; } global $wpdb; $suffix = 2; do { $alt = $slug . '-' . $suffix; $exists = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1", $alt, $post_type, (int) $post_id ) ); $suffix++; } while ( $exists && $suffix < 100 ); return $alt; }, 10, 4 );