Dans énormément de thèmes WordPress que j’audite, functions.php ressemble à un tiroir fourre-tout : hooks d’affichage, requêtes SQL personnalisées, logique de formulaire, configuration de plugins tiers, tout s’y entasse au fil des mois sans structure. Le fichier finit par dépasser les mille, parfois les deux mille lignes, et devient impossible à maintenir sereinement.
Pourtant, rien n’oblige à ce chaos. functions.php reste techniquement un fichier PHP comme un autre, ce qui signifie qu’il peut parfaitement inclure d’autres fichiers, s’organiser en fonctions bien nommées et respecter des conventions strictes. Voici les pratiques que j’applique systématiquement sur mes projets, et les pièges qui reviennent le plus souvent chez mes clients.
Préfixer ou namespacer, sans exception
WordPress ne propose pas nativement d’isolation entre les fonctions d’un thème, d’un plugin et du cœur lui-même : tout partage le même espace de noms global. Déclarer une fonction get_data() dans votre thème est une invitation directe au conflit fatal Cannot redeclare get_data() dès qu’un plugin utilise le même nom.
Deux solutions s’offrent à vous. La plus simple, préfixer systématiquement chaque fonction avec un identifiant unique lié au projet :
<?php
function wpm_get_related_posts( $post_id ) {
// logique de récupération
}
La plus robuste, utiliser un vrai namespace PHP, disponible depuis PHP 5.3 et largement supporté par les hébergements en 2020 :
<?php
namespace WPModerne\Theme;
function get_related_posts( $post_id ) {
// logique de récupération
}
// Appel depuis ailleurs dans le même namespace
$posts = get_related_posts( 42 );
Le namespace a un avantage supplémentaire : il rend les hooks plus explicites lorsqu’on les enregistre avec un tableau de callback, ce qui facilite grandement le débogage.
Bannir la logique métier de functions.php

Le rôle de functions.php est d’initialiser le thème : enregistrer les hooks, déclarer les supports de thème, enqueuer les assets. Ce n’est pas l’endroit pour écrire une requête SQL complexe de trente lignes, un traitement de formulaire de contact ou une intégration API tierce. Cette logique métier mérite ses propres fichiers, clairement identifiés, inclus depuis functions.php plutôt qu’écrits dedans.
Ce découpage n’est pas qu’une question d’esthétique : un fichier trop long devient difficile à relire, à tester et surtout à faire évoluer sans effet de bord. Une fonction perdue au milieu de mille autres est presque invisible lors d’une revue de code.
Organisation recommandée en fichiers inc/
Voici une structure que j’utilise couramment sur mes thèmes sur-mesure :
inc/setup.php:add_theme_support, menus, tailles d’imagesinc/enqueue.php: tous leswp_enqueue_scriptetwp_enqueue_styleinc/hooks.php: lesadd_actionetadd_filterqui modifient l’affichageinc/custom-post-types.php: déclaration des types de contenu personnalisésinc/security.php: durcissement (désactivation de l’API REST anonyme, retrait de la version WordPress, etc.)
Et functions.php se réduit alors à une simple série d’inclusions :
<?php
require get_template_directory() . '/inc/setup.php';
require get_template_directory() . '/inc/enqueue.php';
require get_template_directory() . '/inc/hooks.php';
require get_template_directory() . '/inc/custom-post-types.php';
require get_template_directory() . '/inc/security.php';
Utiliser add_action et add_filter correctement
Les hooks sont le mécanisme central de WordPress, et functions.php en est souvent le principal point d’enregistrement. Une bonne pratique consiste à toujours donner une priorité explicite quand l’ordre d’exécution compte, plutôt que de se fier à la valeur par défaut de 10 :
<?php
add_action( 'wp_head', 'wpm_ajouter_meta_theme_couleur', 5 );
add_filter( 'excerpt_length', 'wpm_longueur_extrait', 20 );
function wpm_ajouter_meta_theme_couleur() {
echo '<meta name="theme-color" content="#1a1a1a">' . "\n";
}
function wpm_longueur_extrait( $longueur ) {
return 30;
}
Évitez aussi les fonctions anonymes pour les hooks que vous pourriez avoir besoin de retirer plus tard avec remove_action : une closure inline est impossible à désinscrire proprement, contrairement à une fonction nommée.
Sécurité : les vérifications qui ne sont jamais optionnelles
Dès qu’un hook dans functions.php traite une entrée utilisateur, que ce soit un formulaire, un paramètre d’URL ou une donnée $_POST, trois réflexes doivent devenir automatiques :
- Vérifier les nonces avec
wp_verify_nonce()avant tout traitement - Échapper toute sortie avec
esc_html(),esc_attr()ouesc_url()selon le contexte - Assainir toute entrée avec
sanitize_text_field()ou l’équivalent adapté au type de donnée
Sur chaque audit, je commence toujours par chercher
$_POSTet$_GETdans functions.php : c’est le meilleur indicateur du niveau de rigueur sécurité d’un thème, bien avant de lire le reste du code.
En résumé
Un functions.php sain n’est pas un fichier court par accident, c’est un fichier court par discipline : namespacing ou préfixage systématique, logique métier déportée dans des fichiers inc/ dédiés, hooks enregistrés avec des fonctions nommées et vérifications de sécurité systématiques sur toute entrée utilisateur. Ces habitudes, une fois prises, ne coûtent rien en temps de développement et évitent des heures de débogage quand le projet grossit.