WordPress · 8 min · publié le 14 mars 2025 · mis à jour le 15 novembre 2025

Thème enfant infecté : pourquoi le changer ne suffit pas

Le thème parent « officiel » est propre, l'enfant contient un `functions.php` retouché ou un fichier qui n'existait pas. Changer de thème et garder l'enfant, c'est emporter la porte. Inspectez les deux, comparez à l'archive d'origine, puis seulement basculez.

Réponse directe

Le parent « officiel » est propre, l'enfant contient functions.php modifié. Les gens changent de thème et gardent l'enfant. Inspectez les deux.

thème enfant malware child theme piraté functions.php child

Parent propre, enfant sale : le malentendu

Les tutos disent de tout personnaliser dans l'enfant pour survivre aux mises à jour du parent. L'attaquant a lu les mêmes tutos. Il pose une vingtaine de lignes dans `functions.php` de l'enfant, ou un `inc/license.php` qui n'a rien à voir avec une licence. Le parent, mis à jour depuis wordpress.org, reste identique à l'officiel. Les scanners qui ne comparent que le parent sont verts.

Beaucoup d'agences livrent un enfant déjà chargé (hooks, CSS, extra JS). Distinguez leur code métier d'un ajout daté du pic d'incident. Les dates de modification et un diff contre le zip de livraison — s'il existe — tranchent. Sans zip d'origine, comparez à un clone local de l'enfant tel que vous le croyez, ou lisez tout fichier PHP de l'enfant : il n'y en a souvent que trois ou quatre.

Un thème « premium gratuit » enfant + parent nulled est un autre dossier : les deux peuvent être sales. Là, on ne « répare » pas l'enfant. On bascule vers un thème sain après export des contenus. Voir WordPress piraté.

L'admin Apparence → Thème affiche l'enfant actif. Désactiver l'enfant sans inspecter le dossier le laisse sur le disque, prêt à être réactivé par un mu-plugin.

functions.php et les includes invisibles

Ouvrez `functions.php` de l'enfant. Cherchez `eval`, `base64_decode`, `gzinflate`, `assert`, `preg_replace` avec `/e`, des `include` vers `wp-tmp`, `radio.php`, un domaine externe, ou un `@include` d'une URL. Une fonction « de cache » ou « de licence » ajoutée en bas du fichier est le classique.

Les `include` / `require` vers des fichiers du même dossier comptent autant que le contenu de `functions.php`. Un `class-loader.php` de 2 Ko illisible n'est pas un autoload Composer oublié — Composer dans un enfant, c'est rare et ça se voit (`vendor/`). En cas de doute, isolez le fichier (renommage hors web) et retestez le site : si tout marche encore, ce n'était pas du métier.

N'effacez pas au jugé un `functions.php` entier : vous perdez menus, tailles d'images, CPT déclarés dans l'enfant. Isolez les ajouts. Copiez le fichier avant.

Ce que « changer de thème » emporte avec soi

Activer Twenty Twenty-Four « pour voir » laisse l'enfant sur le disque et laisse les `theme_mods` de l'ancien thème en base. Un code dans l'enfant ne s'exécute plus tant qu'il n'est pas actif — sauf s'il a déjà copié un mu-plugin ou un drop-in au premier chargement. Beaucoup de payloads font exactement ça : première visite admin, copie vers `mu-plugins`, ensuite l'enfant peut même être « nettoyé ».

Donc : inspectez `mu-plugins`, `advanced-cache.php`, la racine, avant de crier victoire parce que le thème par défaut affiche une home propre. Puis décidez si vous revenez à l'enfant une fois le PHP sain, ou si vous restez sur un thème neuf.

Les widgets et le CSS additionnel suivent parfois le `theme_mods` de l'ancien stylesheet. Un script en base survit au changement de thème. Contrôlez wp_options dans la même vacation.

  • Enfant : tous les PHP lus et datés.
  • mu-plugins et drop-ins : comparés à l'officiel.
  • theme_mods de l'ancien et du nouveau thème : grep script.

Comparer à l'archive, pas au feeling

Si l'agence a livré un zip, c'est la référence. Un diff (fichiers + hash) est plus fiable qu'une relecture à 23 h. Si le zip d'origine est déjà infecté (nulled, « pack 50 thèmes »), la référence est un thème sain équivalent, pas ce zip.

Les fichiers de traduction, les `.json` de patterns, les captures `screenshot.png` sont rarement le payload. Priorisez `*.php`, puis `*.js` dans l'enfant, puis les images aux doubles extensions. Un `logo.php.jpg` dans `assets/` de l'enfant est une porte.

style.css n'est pas le seul fichier

`style.css` porte l'en-tête `Template:` qui lie l'enfant au parent. Il est rarement infecté (un CSS n'exécute rien côté serveur). En revanche `functions.php`, `header.php` / `footer.php` copiés dans l'enfant « pour surcharger », `js/custom.js`, et n'importe quel template WooCommerce copié (`checkout/form-billing.php`) sont des cibles. Un skimmer dans le template de checkout de l'enfant est plus grave qu'un lien spam dans le footer. Testez le tunnel — skimmer WooCommerce.

Un enfant qui surcharge `woocommerce/` doit être relu comme un module de paiement, pas comme « un peu de CSS ».

theme_mods qui restent après bascule

Changer de thème ne vide pas `theme_mods_ancienenfant`. Un attaquant qui a mis le script là, et un site qui réactive l'enfant plus tard, ressort le script. Grep ces options même si l'enfant est désactivé. Exportez, nettoyez, ou supprimez l'option après copie si vous abandonnez ce thème pour de bon.

Mu-plugin copié depuis l'enfant

Cherchez dans `mu-plugins` un fichier dont la date colle à l'incident ou dont le contenu ressemble à l'ajout de l'enfant. C'est la persistance. L'enfant peut alors sembler « déjà nettoyé » par un premier prestataire. Reliez les deux hashes. Retirez le mu-plugin après export, pas l'inverse (sinon l'enfant le recreuse au prochain hit si le code de copie est encore là).

Remettre un enfant sain sans perdre la mise en page

Une fois le PHP aligné sur l'archive saine, réactivez, videz les caches, parcourez home, une page builder, le checkout. Recréez le CSS additionnel depuis vos notes, pas depuis un backup d'options non lu. Les images du customizer peuvent rester : ce sont des IDs média, pas du PHP.

Si l'enfant n'a plus de référence saine et que le métier tient en CSS + quelques hooks, recréez un enfant neuf et re-collez uniquement ce que vous comprenez. C'est plus court que de « nettoyer » 80 fichiers d'un starter vendu sur ThemeForest en 2019.

Quand il vaut mieux abandonner l'enfant

Enfant nulled, sans zip d'origine, avec dix includes opaques : changez de thème après export des contenus et des réglages visuels (captures). Le coût d'une relecture ligne à ligne dépasse souvent une reconstruction. Refermez ensuite users, panel, FTP — le thème n'était que le logement.

Vous pouvez faire inspecter parent et enfant si le diff dépasse ce que vous voulez assumer. Le prix s'affiche avant l'accès serveur.

  • Tous les PHP de l'enfant lus ou remplacés.
  • Aucune copie dans mu-plugins / racine.
  • theme_mods greppés.
  • Checkout et pages clés revus en navigation privée.

Questions fréquentes

Mettre à jour le thème parent retire-t-il l'infection de l'enfant ?

+
Non. C'est tout l'intérêt de l'enfant : il n'est pas écrasé. La maj du parent est utile pour les failles du parent, inutile contre un `functions.php` d'enfant retouché.

Puis-je supprimer le dossier de l'enfant et en recréer un vide ?

+
Oui si vous acceptez de perdre hooks et templates de l'enfant. Exportez d'abord, et vérifiez qu'aucun mu-plugin n'a été copié. Recréez l'en-tête `Template:` correctement sinon WordPress ignorera l'enfant.

L'enfant n'a que style.css. Suis-je concerné ?

+
Moins pour l'exécution PHP. Contrôlez quand même qu'il n'y a pas d'autres fichiers cachés, et que les theme_mods / widgets n'injectent pas de JS. Un enfant « CSS only » reste une cible d'options.

Le parent est un thème premium acheté. Je dois le racheter ?

+
Non pour le nettoyage. Téléchargez le zip de votre compte marketplace et comparez. Un zip « trouvé » n'est pas une licence et n'est pas une référence saine.

Un builder (Elementor) dans l'enfant change-t-il la méthode ?

+
Le builder vit surtout en base (données de pages). L'enfant peut quand même porter un PHP de skimmer ou un extra JS. Contrôlez les deux : templates enfant et contenus builder.
À lire ensuite
JavaScript dans wp_options Migration qui ramène l'infection Skimmer WooCommerce WordPress piraté Porte dérobée PHP Déclarer mon site