Un client nous appelle un jeudi matin. Son site WordPress, 400 articles bien indexés, venait de passer intégralement en noindex dans la nuit. Le coupable ? Un plugin SEO populaire, mis à jour automatiquement la veille, qui avait réécrit la balise robots de toutes les pages. Le correctif a pris quatre heures. L’audit interne, lui, a duré une semaine : on a décidé de supprimer tous les plugins SEO du périmètre et de gérer ça dans le thème. On vous montre comment, sans dépendre d’une mise à jour qui vous fera perdre 60% de votre trafic organique.
Un titre sur chaque page, sans déléguer la décision
WordPress a corrigé un défaut historique : depuis la version 4.1, il suffit d’ajouter add_theme_support('title-tag') dans le functions.php pour que le CMS génère un <title> propre, concaténant le titre de l’article et le nom du site. Vous avez probablement cette ligne. Elle est nécessaire, mais pas suffisante.
Pour un contrôle absolu, on va utiliser un champ personnalisé. L’idée : dans l’écran d’édition d’un article, un champ custom_title permet au rédacteur ou au référenceur de saisir une balise title exacte, mot pour mot. Si ce champ est rempli, c’est lui qu’on envoie au navigateur et à Googlebot. Sinon, on laisse le comportement par défaut.
Ouvrez le header.php de votre thème enfant. Juste avant la fermeture de la balise <head>, on écrit ceci :
if ( is_single() || is_page() ) {
$custom_title = get_post_meta( get_the_ID(), 'custom_title', true );
if ( ! empty( $custom_title ) ) {
echo '<title>' . esc_html( $custom_title ) . '</title>';
} else {
wp_title( '|', true, 'right' );
}
}
On garde wp_title comme fallback, il se chargera du titre natif. Si vous voulez pousser plus loin, filtrez pre_get_document_title depuis functions.php plutôt que d’éditer le header.
Une meta description par page, pas une phrase tronquée au petit bonheur
Laisser WordPress générer une meta description automatique, c’est souvent lui faire prendre les 160 premiers caractères du contenu, sans contexte. Pas idéal quand votre introduction commence par une question ou une citation.
On va utiliser le même principe de champ personnalisé : un champ meta_description que l’on remplit directement dans l’interface d’édition. Dans le header.php, après le <title>, on ajoute :
if ( is_single() || is_page() ) {
$desc = get_post_meta( get_the_ID(), 'meta_description', true );
if ( $desc ) {
echo '<meta name="description" content="' . esc_attr( $desc ) . '" />';
} elseif ( is_single() && ! empty( $post->post_excerpt ) ) {
echo '<meta name="description" content="' . esc_attr( wp_strip_all_tags( $post->post_excerpt ) ) . '" />';
} else {
// fallback silencieux : pas de meta description, Google se débrouillera avec le contenu
}
}
On introduit un deuxième fallback : l’extrait personnalisé, que WordPress appelle déjà. S’il est renseigné, il sert de description. Sinon, on ne met rien. Mieux vaut aucune meta description qu’une balise automatique qui fait doublon avec les premières phrases de l’article et que Google va de toute façon ignorer.
💡 Conseil : Les champs personnalisés se créent en deux lignes dans
functions.phpavecregister_meta(). Si vous ne voulez pas coder, un simple groupe ACF local suffit, mais on est hors-sujet ici.
Les meta keywords sont mortes, et on va vous dire pourquoi on en parle quand même
Oui, Google ne les utilise pas pour le classement. Bing non plus. Mais on remarque un usage de niche qui peut avoir du sens si vous maintenez un moteur de recherche interne avec Relevanssi ou une extension similaire : les meta keywords, bien structurées, peuvent pondérer une recherche locale. Ce n’est pas un levier de trafic, c’est un levier d’ergonomie.
Si vous décidez de les garder pour cet usage très précis, le principe est identique : champ personnalisé meta_keywords, insertion dans le header.php. Mais on vous conseille surtout de ne pas perdre une seconde de plus sur ce sujet. Passez à la suite.
Nettoyez vos H1 comme on nettoie un fichier robots.txt oublié
Un thème WordPress standard affiche souvent le nom du site en <h1> sur la page d’accueil, puis un logo cliquable en <h1> sur toutes les autres pages, reléguant le titre de l’article en <h2>. Résultat : sur un site de 200 articles, vous avez 200 pages avec exactement le même <h1>. Les algorithmes d’analyse de contenu voient un site qui répète un titre unique, pas un site avec une hiérarchie sémantique claire.
Ouvrez de nouveau le header.php. Cherchez la portion qui affiche le logo ou le titre du site. Enveloppez-la dans une condition :
if ( is_front_page() || is_home() ) {
echo '<h1>' . get_bloginfo('name') . '</h1>';
} else {
echo '<p class="logo">' . get_bloginfo('name') . '</p>';
}
Sur les pages intérieures, le <h1> devient un simple paragraphe stylé. Le vrai <h1> de la page, c’est le titre de l’article, que WordPress envoie déjà dans la boucle (the_title()). Vous venez de rendre à votre contenu la prééminence qu’il mérite.
Structurez vos articles avec les vraies balises HTML, pas avec des artifices visuels
Trop d’éditeurs WordPress utilisent l’interface Gutenberg en mettant une phrase en gras et en taille 24px pour simuler un intertitre. C’est une erreur qui se paie en indexation. Sans balise <h2> ou <h3>, les moteurs ne perçoivent pas le plan du document. Ils traitent l’article comme un bloc de texte indistinct.
Ce qu’on fait :
- un seul
<h1>par page, le titre de l’article ; - chaque section majeure ouvre par un
<h2>structurant ; - les sous-sections, si nécessaires, utilisent
<h3>, jamais de saut de niveau (pas deh2suivi d’unh4) ; - les phrases en gras se font avec
<strong>, pas avec unspangras, parce que<strong>a une sémantique d’importance qui aide les crawlers à pondérer les idées clés.
Et si un jour vous voulez changer le style de tous les intertitres, vous modifiez une ligne de CSS. Pas 200 blocs Gutenberg un par un. C’est un gain de dette technique qui dépasse le seul SEO.
À ce stade, votre thème a une base propre. Pas de plugin qui décide à votre place. La prochaine partie traitera des URL, du fichier robots.txt et du sitemap XML, toujours sans extension. On tient à ce que vous sachiez exactement ce que votre site déclare aux moteurs, ligne par ligne.
📌 À retenir : Appliquer ce nettoyage de structure prend une heure sur un thème classique. Pour un site en production, faites-le d’abord sur un environnement staging ; un
h1mal fermé et votre page d’accueil tombe en erreur.
Questions fréquentes
Pourquoi ne pas simplement utiliser un plugin comme Yoast SEO ou Rank Math ?
Ces plugins font bien plus que ce dont 80% des sites ont besoin. Ils ajoutent du poids à l’admin, des requêtes à chaque page, et introduisent un risque de régression à chaque mise à jour automatique. Si vous n’exploitez pas le breadcrumb JSON-LD, les redirections avancées et l’analyse sémantique, vous gardez une usine à gaz pour deux balises meta. Coder ces deux balises vous rend totalement autonome.
J’utilise un thème FSE (Full Site Editing), je n’ai pas de header.php. La méthode tient-elle ?
Oui, le principe est transposable. Avec un thème FSE, vous interviendrez via un hook wp_head dans functions.php pour injecter les balises conditionnelles. Le nettoyage du H1 se fait directement dans l’éditeur de template, en conditionnant l’affichage du titre du site selon le contexte avec le bloc approprié. La logique métier reste la même ; seul le point d’ancrage change.
Cette approche est-elle compatible avec l’état global de mon app React montée dans WordPress ?
Si vous utilisez une headless config où WordPress fournit des données à une app React, la génération des balises meta se fait côté front. La philosophie est identique à celle du state management : vous déclarez vos champs custom sur l’API REST, vous les lisez côté React, et vous peuplez le <head> avec React Helmet ou un équivalent. C’est la logique Zustand appliquée au SEO : un store simple, explicite, sans magie. On a détaillé cette approche avec Zustand ici.