Avant toute chose, l'astuce que je vais révéler dans cet article peut être appliquée à tout type de site web et pas uniquement à WordPress. Par ailleurs, sachez qu'il vous faudra tout de même quelques compétences en développement pour tout suivre. Je vais m'efforcer d'expliquer tout en détail comme j'en ai l'habitude, mais à un certain point, il me faudra prendre certaines décisions pour éviter que cet article fasse 3 km de haut ! Ainsi, je vais considérer que toute personne s'attaquant à la lecture sait appeler un fichier javascript, installer une bibliothèque, etc. Bien sûr, si vous avez la moindre question, la section des commentaires est là.

Les Faits

Il n'y a aucun scoop à vous dire que les créateurs de spam et leurs opposants sont en guerre, très certainement depuis les débuts de l'Internet. Le sujet est de taille et beaucoup (sérieusement, vraiment beaucoup) d'argent est à la fois généré et perdu dans cette bataille.
Pour les spammeurs (sans même parler des e-mails), il s'agit de développer des méthodes pour trouver les formulaires sur les forums et autres sites web, afin d'y automatiser le post de publicités et hameçonnages (en utilisant des bots, etc.).
WordPress et sa fonctionnalité de commentaires est évidement une cible de choix pour eux. Ainsi, par défaut, WordPress est installé avec un plugin très efficace contre les spams : Akismet. Une fois paramétré, Akismet va détecter si un nouveau commentaire posté est un spam ou non et en fonction de vos réglages, va silencieusement l'effacer ou le placer dans une catégorie dédiée (auto effacée tous les quinze jours). Akismet est si efficace pour détecter les spams (grâce à son énorme base de données) qu'il est incontournable.

Cependant, en ce qui me concerne, quelque chose ne va pas : le plugin travaille après coup, de fait, il n'empêche pas un bot de poster. Ainsi, pour chaque action d'un bot, un incroyable nombre de requêtes est généré sur votre site ; celles pour accéder au site, celles pour poster un commentaire, celles d'Akismet pour le traiter, etc. Ne serait-il pas plus simple d'empêcher les bots de physiquement accéder au formulaire et poster (ou au moins d'essayer) ? Cela permettrait de rediriger la puissance du serveur à des tâches qui font sens, comme simplement servir vos pages à vos visiteurs plus efficacement :)

Comment réduire dramatiquement les spams sur WordPress

Extrait des mes statistiques Akismet sur deux ans

Statistiques Akismet Tazintosh

Début juin 2015, j'ai mis à jour mon site pour tester une simple astuce (utilisant un fichier .htaccess) trouvée sur l'Internet. Elle permet d'empêcher les bots d'appeler directement le formulaire de réponse wp-comments-post.php. Entre juin et août 2015, on peut constater quelques effets.
Mais en septembre 2015, j'ai implémenté ma nouvelle idée (à l'origine de cet article) dans mon propre thème. Il s'agissait d'un simple test, mais les résultats ci-dessus n'ont je pense guère besoin d'être expliqués.

Dans les faits, l'astuce est très simple. Si vous ne l'avez pas encore fait (sinon rafraichissez la page), faites défiler jusqu'à la fin de cet article ; avec un soupçon d'attention, vous allez remarquer que le formulaire de réponse et les commentaires ne sont pas chargés. Dès que leur zone d'affichage entre dans la vue de votre navigateur, une requête Ajax est envoyée au serveur pour les charger. Le défilement est quelque chose que les bots ne savent pas faire, donc logiquement, en visitant la page, il n'y aucun forumulaire où poster. Boum, simple, efficace.
Bien sûr, le fait que la requête soit liée au défilement est un choix par design. Il est évident que sur certains articles, si le contenu est trop court ou que la fenêtre de navigateur d'un utilisateur est trop haute, la section des commentaires va immédiatement s'afficher, n'empêchant pas le post de spam. Ainsi, la solution basée sur le défilement ne peut pas —tout— empêcher, mais c'est bon pour moi, car il faut toujours considérer et mettre dans la balance le confort d'utilisation de vos lecteurs. Une méthode immédiatement plus radicale serait de déclencher l'affichage en demandant de cliquer sur un bouton. Je considère cela trop intrusif pour l'utilisateur. Au final, c'est à vous de décider.
Trève de paroles, réglons leur compte aux spams!

Étape 1 : .htaccess. Empêcher l'accès direct au formulaire de réponse.

Voici le code à ajouter à votre fichier .htaccess, situé à la racine de votre installation WordPress. Changer le tazintosh.com par votre propre nom de domaine (ligne 9).

# -----------------------------------------------
# Anti Spam (prevent direct usage of wp-comments)
# -----------------------------------------------
<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteCond %{REQUEST_METHOD} POST
	RewriteCond %{REQUEST_URI} .wp-comments-post.php*
	RewriteCond %{HTTP_REFERER} !^$
	RewriteCond %{HTTP_REFERER} !.tazintosh.com.* [OR]
	RewriteCond %{HTTP_USER_AGENT} ^$
	RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]
</IfModule>

Étape 2 : l'astuce Ajax

Il va falloir éditer certains fichier de votre thème. Si comme moi, vous avez intégralement créé votre propre thème, cela va être encore plus simple. En bref, il s'agit d'empêcher la section des commentaires d'être générée par certains fichiers PHP. La plupart du temps, les commentaires sont générés dans les fichiers single.php et page.php (cf. le Codex WordPress pour en apprendre davantage.

Empêcher la génération par défaut de la section des commentaires

Rechercher quelque chose de similaire à cela dans vos fichiers :

<?php
if ( comments_open() || get_comments_number() ) :
	comments_template();
endif;
?>

Commenter ou effacer ces lignes. Rappel : si vous modifiez un thème que vous n'avez pas développé, toute mise à jour du dit thème effacera vos modifications. Je vous laisse prendre soin de gérer cela, soit en faisant des sauvegardes des fichiers modifiés, soit en utilisant Subversion, etc.

<?php
// if ( comments_open() || get_comments_number() ) :
// 	comments_template();
// endif;
?>

Une fois cette modification faite, si vous rechargez votre site, la section des commentaires ne devrait plus se charger. Il faut maintenant modifier le fichier comments.php et créer une nouvelle fonction qui sera appelée par Ajax.

Modification de comments.php

Si vous jetez un œil à ce fichier dans les thèmes de base de WordPress tels que twentyfifteen, twentyfourteen, twentysixteen, il contient notamment <div id="comments">[…]</div>. Nous allons simplement englober cela par une nouvelle fonction et remplacer les lignes 14 à 16 par le code de votre modèle de commentaires.

<?php
function taz_loadComments(){
	global $comments_post_id;
	$comments_post_id = $_GET['theid'];
	global $comments_post_id;

	$args = array(
		'post_id' => $comments_post_id
	);
	$comments_query = new WP_Comment_Query;
	$comments = $comments_query->query($args);
?>

	<div id="comments">
		<!-- […] -->
	</div>

<?php
	die();
}
add_action('wp_ajax_nopriv_loadComments', 'taz_loadComments'); // If user not logged in
add_action('wp_ajax_loadComments', 'taz_loadComments'); // For logged in user
?>

Désormais, on va créer la fonction javascript qui va charger la section des commentaires en Ajax, uniquement au besoin. Si vous utilisez un thème qui supporte l'ajout de javascript personnalisé (custom javascript), c'est probablement là qu'il vous faudra mettre le code suivant.

Chargement de la section des commentaires en Ajax

$.ajax({
	url: '/wordpress/wp-admin/admin-ajax.php',
	type: 'GET',
	dataType : 'html',
	data: {
		action: 'loadComments',
		theid: BODY.data('id'); // See note*
	}
}).done(function(data){
	if (data !== 0){
		// The code to append the comments, i.e. $('.parentToAppendTo').append(data), and anything else you need.
	} else {
		// What to do in case of error.
	}
});
<?php
if (in_array('blog',$classes)) {
	$documentId = get_option('page_for_posts');
} else {
	$documentId = get_the_ID();
}
?>

<body data-id="<?php echo $documentId ?>">
<!-- […] -->
$(document).ready(function(){ // The following code must run on DOM Ready

	if (!BODY.hasClass('blog') && !BODY.hasClass('archive') && !BODY.hasClass('search')){
		var commentsController = new ScrollMagic.Controller(); // Init controller
		// Build scene
		new ScrollMagic.Scene({triggerElement: ".taz_mainSection-footer", triggerHook: 'onEnter'})
			.addTo(commentsController)
			.reverse(false)
			.on("start", function () {
				$.ajax({
					url: '/wordpress/wp-admin/admin-ajax.php',
					type: 'GET',
					dataType : 'html',
					data: {
						action: 'loadComments',
						theid: BODY.data('id');
					}
				}).done(function(data){
					if (data !== 0){
						$('.taz_mainSection-footer').append(data);
						// Other stuffs going on here.
					} else {
						console.log("Error");
					}
				});
			});
	}

});

Je crois que l'on y est… Nous avons ajouté une nouvelle règle au fichier .htaccess pour empêcher l'accès direct au formulaire et modifié quelques modèles du thème pour éviter la génération directe de la section des commentaires en laissant ce travail à notre fonction Ajax. À partir de maintenant, je ne vois pas de raison pour que vous n'obteniez pas des statistiques similaires aux miennes. Je suis conscient que cela aura représenté un peu de travail, mais, sérieusement, chaque minute en vaut la peine. Profitez de votre site sans spam !