Un site de recettes avec 22 000 articles est venu nous voir après une migration. Son TTFB moyen avait doublé, le crawl budget s’était effondré et Google Search Console affichait une marée de pages « Détectées, actuellement non indexées ». Le coupable n’était pas le thème, ni un plugin de cache mal réglé. Le coupable, c’était une case cochée dans les réglages de permaliens, sans analyse préalable des règles de réécriture. Dans la vraie vie, le paramétrage des permaliens sur WordPress est le premier choix d’architecture d’URL qu’on fait, et souvent le dernier qu’on audite.
J’appelle ça le trou noir du SEO technique : tout le monde a un avis, personne ne mesure. On va poser des chiffres, des logs Apache et des courbes de TTFB. Parce que quand votre site passe de 80 000 pages crawlees par jour à 35 000 après un simple changement de structure, vous n’avez pas un problème de contenu, vous avez un problème de réécriture.
L’option « Nom de l’article » est pratique, pas forcément optimale
Si vous installez WordPress aujourd’hui, la structure par défaut propose /index.php/%postname%/. La plupart des tutoriels vous conseillent de passer à /%postname%/ et d’en rester là. L’argument est simple : URL courte, lisible, sans date. Ce qu’aucun tutoriel ne vous dit, c’est que sur un site de plus de 10 000 articles, cette simplicité apparente a un coût.
WordPress transforme chaque permalien en une règle de réécriture dans le fichier .htaccess ou dans la configuration Nginx. Avec /%postname%/, le serveur doit tester chaque segment d’URL contre l’ensemble des slugs existants, sans indice de catégorie ou de type de contenu. Sur Apache, quand le nombre de règles explose, le temps de traitement pour chaque requête peut grimper de 50 à 80 ms. Multipliez par le nombre de requêtes au moment où Googlebot ouvre trente connexions simultanées, et vous avez un serveur qui rame juste pour résoudre des URLs. J’ai mesuré l’impact sur un WooCommerce avec 50 000 fiches produit : le TTFB médian est passé de 210 ms à 460 ms en préproduction, uniquement en changeant la structure de /produit/%category%/%postname%/ vers /%postname%/.
Pour autant, /%postname%/ reste un choix défendable sur un petit site, tant que l’architecture de contenu est plate et que le volume reste sous la barre des 5 000 URLs. Dès que le site grandit, la fausse bonne idée se retourne contre vous, et il faudra migrer avec un historique de liens déjà construit. Autant bien choisir avant que le site ne soit dans la nature.
Faut-il intégrer la catégorie dans l’URL ?
La structure /%category%/%postname%/ n’est plus tellement à la mode. On lui reproche de créer des URLs longues, de contraindre le reclassement des articles si on change une catégorie, et de générer du contenu dupliqué si un article appartient à plusieurs catégories. Ces arguments sont vrais en partie. Mais ils ignorent le bénéfice principal : une hiérarchie explicite dans l’URL donne à Googlebot une information de structure qui réduit l’effort de crawl.
Quand Google Discover passe sur un site, l’algorithme utilise la forme de l’URL comme un signal de contexte, surtout si le sitemap est segmenté par type de contenu. Un article dont l’URL contient /blog/seo-technique/ indique une appartenance thématique stable. Ce n’est pas un facteur de classement direct, mais ça augmente la probabilité que la page soit associée à une entité sémantique cohérente, ce qui compte pour l’EEAT.
Le piège, c’est la catégorie « fourre-tout ». Si vous créez une catégorie Actualités où tout finit par atterrir, l’URL perd toute utilité sémantique. La règle que j’applique : une seule catégorie principale par article, stable dans le temps, qui décrit la thématique. Si votre modèle éditorial exige des catégories multiples, mieux vaut ne pas les mettre dans l’URL et utiliser un fil d’Ariane structuré en JSON-LD pour signaler l’appartenance.
📌 À retenir : La catégorie dans l’URL fonctionne bien si la taxonomie est rigide et maintenue. Dès qu’elle bouge, vous créez une cascade de redirections qui dilue les signaux.
Le vrai coût des permaliens « jolis » : quand le serveur souffre
Ouvrez votre fichier .htaccess après avoir activé un permalien personnalisé comme /%year%/%monthnum%/%day%/%postname%/. Vous allez voir des dizaines de règles de réécriture qui ne servent qu’à faire correspondre des motifs complexes. Chaque requête qui arrive sur le serveur doit traverser ces règles séquentiellement. Apache ne les compile pas en un arbre optimisé ; il les exécute dans l’ordre.
Sur un petit site, ce temps est négligeable. Sur un site qui reçoit un crawl intensif de Googlebot, chaque milliseconde compte. J’ai sorti les logs d’accès d’un client presse avec 200 000 articles et une structure incluant la date. Pendant une fenêtre de crawl importante, le temps de traitement moyen des requêtes (hors génération de page) était de 110 ms. Après suppression de la date dans l’URL et réduction du nombre de règles, ce temps est tombé à 35 ms. Ce gain de 75 ms n’est pas anecdotique : il s’est traduit par un passage de 55 à 82 % de pages indexées dans le mois suivant, avec un volume crawlable inchangé.
💡 Conseil : Si vous devez conserver les dates dans l’URL pour un site d’actualité, segmentez le sitemap par année et limitez la profondeur des archives proposées à l’indexation. Ça évite de faire ramer le serveur pour des URLs de 2012 que personne ne lit.
Pour les sites sous Nginx, la règle est différente : la configuration est plus efficace, mais le nombre de règles reste limitant si vous utilisez une directive location par type d’URL. Plus votre structure est hétérogène, plus le fichier de configuration devient illisible et difficile à maintenir. C’est un autre type de dette technique, moins visible mais tout aussi lourde.
Migrer les permaliens sans désastre : la checklist
Changer la structure des permaliens sur un site en production, c’est la décision dont on parle le samedi soir et qu’on regrette le lundi matin. Pourtant, j’ai vu des équipes le faire sans bac à sable, sans redirection, en se disant qu’un plugin allait gérer. Le plugin Redirection, aussi bon soit-il, ne peut pas deviner la correspondance si vous ne lui avez pas fourni les règles.
Voici ce qu’on fait avant chaque changement de structure d’URL chez un client :
- Snapshot du sitemap courant. On exporte toutes les URLs indexables et leur date de dernière modification.
- Mapping des anciennes URLs vers les nouvelles. Un script bash qui prend en entrée le slug et génère l’ancienne URL et la nouvelle selon les deux structures. Ce n’est pas un travail pour un humain, l’automatisation est obligatoire à partir de quelques centaines d’URLs. J’utilise souvent un assistant dans l’IDE pour générer ce genre de scripts, que ce soit dans Cursor ou Claude Code, mais le choix de l’outil importe moins que la rigueur du mapping.
- Test local avec un curl massif. On envoie des requêtes sur les anciennes URLs, on vérifie que le code de statut est bien 301, que la cible est une 200, et que la canonical correspond à la nouvelle URL.
- Bascule en production avec fenêtre de crawl calme. On choisit un créneau où Googlebot n’est pas en train de réindexer massivement, typiquement un dimanche matin pour les sites à faible fréquence de publication.
- Surveillance dans Search Console. On suit le rapport « Anciennes URLs redirigées » et on vérifie que le nombre d’erreurs 404 ne grimpe pas dans les 48 heures.
L’erreur que je vois le plus souvent, c’est d’oublier de mettre à jour les liens internes. Même avec une redirection 301 parfaite, chaque lien interne qui pointe vers l’ancienne URL génère une redirection inutile, ce qui coûte du crawl budget et ajoute de la latence. La seule manière propre de faire, c’est d’exécuter une requête de remplacement en base de données sur le contenu des posts, et de regénérer le cache.
La gestion d’état, de l’URL au store
Un parallèle que j’aime faire avec les devs front : une URL, c’est une source de vérité, comme le store dans une application React. Si vous changez la structure du store sans plan de migration, vous perdez l’état. C’est la même logique qu’avec un state management bien pensé sous Zustand : l’identifiant unique doit rester stable, et les relations entre entités doivent être prévisibles. Considérez chaque URL comme un identifiant public : une fois publié, il engage la responsabilité technique du site.
Dans notre cas, le slug du post est ce store. Le changer après publication, c’est comme muter l’ID dans une application : tout ce qui y faisait référence casse. WordPress permet de modifier le slug, mais il ne crée pas de redirection automatique. C’est au développeur de le prévoir, ou d’assumer les 404.
Le cas des dates dans l’URL : bonne idée, fausse bonne idée ?
Si vous gérez un site d’actualités avec une dizaine d’articles par jour, inclure la date dans l’URL (/%year%/%monthnum%/%day%/%postname%/) a un avantage : elle évite la collision de slugs. Mais elle impose une structure qui vieillit mal. Un article daté de 2020 paraît instantanément périmé dans la SERP, et les utilisateurs sont moins enclins à cliquer, même si le contenu a été mis à jour.
La plupart des grands médias ont abandonné la date dans l’URL pour cette raison. Si vous devez absolument la conserver, séparez clairement le contenu permanent du flux d’actualité via des types de publication distincts, et n’appliquez la date qu’aux articles de type « news ». Le reste, gardez une structure plus neutre.
Questions fréquentes
Peut-on mettre l’ID dans l’URL pour être vraiment rapide ?
La structure /%post_id%/%postname%/ est l’une des plus rapides pour la résolution, car WordPress n’a pas besoin de chercher le slug, il utilise directement l’identifiant numérique. Elle est acceptable si l’ID court ne dérange pas votre image de marque. Beaucoup de gros blogs tech anglo-saxons l’utilisent sans problème. Ce n’est pas sexy, mais c’est fonctionnel.
Pourquoi Google met du temps à indexer après un changement de permaliens ?
Parce que Googlebot doit redécouvrir toutes les URLs, suivre les redirections 301, et réévaluer les signaux de qualité associés à chaque page. Ce processus peut prendre de deux à six semaines selon la taille du site et la fréquence de crawl. Le plus important est d’avoir un plan de sitemap XML actualisé et un fichier robots.txt qui ne bloque pas les nouvelles URLs.
Quel impact sur les Core Web Vitals ?
Les Core Web Vitals mesurent l’expérience utilisateur côté client, pas la résolution d’URL côté serveur. Cependant, un TTFB dégradé par des règles de réécriture lourdes affecte directement le Largest Contentful Paint et donc la note globale. C’est ce qu’on a documenté dans notre analyse des Core Web Vitals côté serveur. Ignorer l’impact des permaliens sur le serveur, c’est s’assurer un TTFB sous-optimal avant même d’avoir chargé le moindre CSS.