mirror of
https://github.com/R0m1k3/PleinR.git
synced 2026-10-23 23:28:04 +02:00
SEO : URLs de fiche parlantes, pages métier indexables, aides de rédaction
- Fiches adhérents : URL canonique /adherents/12-au-bon-pain-frouard (memberPath). L'identifiant en tête suffit ; /adherents/12 et tout slug périmé sont redirigés de façon permanente vers la forme canonique, donc les anciens liens et les partages sociaux restent valides. Tous les liens (accueil, carrousel, annuaire, JSON-LD, sitemap, publications Facebook / LinkedIn) passent par memberPath. - Pages métier /annuaire/[categorie] : une page indexable par catégorie avec titre, introduction (effectif, communes), grille d'adhérents, fil d'Ariane et ItemList. Sans adhérent : noindex et hors sitemap. Section « Parcourir par métier » sur l'annuaire et « Autres métiers » sur chaque page pour le maillage interne. - Composants partagés MemberCard et CategoryLinks ; slugify déplacé dans src/lib/slug.ts. - Backend : conseils de rédaction sous les champs description et tags des formulaires adhérent (espace adhérent et fiche staff). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDbKbJrPWweXXYSxA8MXW7
This commit is contained in:
19 files changed
+489
-99
No files matched your search
@@ -10,6 +10,7 @@ import { signOut } from "@/auth";
|
||||
import { getSession } from "@/lib/session";
|
||||
import { db } from "@/db";
|
||||
import { CATEGORY_PALETTE } from "@/db/categories";
|
||||
import { slugify } from "@/lib/slug";
|
||||
import {
|
||||
activityLog,
|
||||
categories,
|
||||
@@ -45,15 +46,6 @@ import { SITE_SETTING_DEFAULTS } from "@/lib/site-settings";
|
||||
import type { AppRole } from "@/types/next-auth";
|
||||
|
||||
|
||||
function slugify(input: string): string {
|
||||
return input
|
||||
.normalize("NFD")
|
||||
.replace(/[̀-ͯ]/g, "")
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.slice(0, 70);
|
||||
}
|
||||
|
||||
async function logActivity(message: string, dot = "#2C6FB3") {
|
||||
// Le message agrège des saisies de tiers : on ne laisse passer que <strong>.
|
||||
@@ -127,7 +119,7 @@ function revalidatePromoPaths(memberId?: number | null) {
|
||||
revalidatePath("/backend");
|
||||
revalidatePath("/");
|
||||
revalidatePath("/annuaire");
|
||||
if (memberId) revalidatePath(`/adherents/${memberId}`);
|
||||
if (memberId) revalidatePath("/adherents/[id]", "page");
|
||||
}
|
||||
|
||||
/** Réseaux demandés pour une promo, dans l'ordre d'affichage. */
|
||||
@@ -168,6 +160,7 @@ async function publishPromoShares(
|
||||
imageUrl: promotions.imageUrl,
|
||||
memberId: promotions.memberId,
|
||||
memberName: members.name,
|
||||
memberCity: members.city,
|
||||
})
|
||||
.from(promotions)
|
||||
.leftJoin(members, eq(promotions.memberId, members.id))
|
||||
@@ -550,7 +543,7 @@ export async function updateMember(formData: FormData) {
|
||||
.where(eq(members.id, id));
|
||||
|
||||
revalidatePath("/backend/adherents");
|
||||
revalidatePath(`/adherents/${id}`);
|
||||
revalidatePath("/adherents/[id]", "page");
|
||||
revalidatePath("/");
|
||||
}
|
||||
|
||||
@@ -1104,7 +1097,7 @@ export async function updateOwnProfile(formData: FormData) {
|
||||
.where(eq(members.id, memberId));
|
||||
|
||||
revalidatePath("/backend/espace");
|
||||
revalidatePath(`/adherents/${memberId}`);
|
||||
revalidatePath("/adherents/[id]", "page");
|
||||
revalidatePath("/annuaire");
|
||||
revalidatePath("/");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user