Supprimer les liens de spam dans les commentaires

Le code snippet du jour permet de supprimer automatiquement les liens contenus dans les commentaires en fonction de la longueur du message et de l’ancienneté de l’article.

Pourquoi filtrer les liens dans les commentaires ?

Si vous avez un blog avec des visiteurs réguliers, vous vous êtes certainement rendu compte que la modération des commentaires prend un certains temps. L’idée d’automatiser le processus de modération est donc assez logique : laissons WordPress supprimer les spams postés par des robots, et passons notre temps à écrire des articles et répondre aux vrais messages, c’est plus intéressant !

Notre CMS met à disposition quelques réglages pour filtrer l’approbation d’un commentaire, dans la partie « Réglages → Discussion » de l’administration :

Par défaut, il est possible de :

En plus de ces réglages, il est possible d’installer des barrières anti-spams supplémentaires telles que le plugin Akismet qui filtre les spams connus de sa base de données. C’est très efficace pour bloquer les spams de type site coquin, viagra ou pilules… (sur Wabeo, Akismet à déjà bloqué 384 235 messages, merci à lui 😉)

L’astuce de développement du jour correspond à un autre système de filtrage que j’ai souhaité mettre en place sur mon site. Je n’aime pas modérer manuellement les commentaires, ça prend du temps que je pourrais utiliser autrement. Et en même temps ça m’embête de laisser passer des liens spammy dans les commentaires du type :

Coucou, super cet article ! Merci pour le partage ;)
– par site-immobilier <http://creation-site-immo.truc>

Ce qui me gène ici, c’est le ratio « 8 mots, 1 lien »…
Si on valide ça tel quel, la section commentaires aura vite fait de devenir une ferme de backlinks ; Autant de liens qui viendront diluer le jus SEO de votre article, et probablement affaiblir le maillage interne de votre site.

Autoriser les liens en fonction de la longueur du commentaire

Un lien, ça se mérite ! L’idée est de permettre au rédacteur d’un commentaire de déposer un lien (lien sur son nom inclus) pour 50 mots écrits. S’il écrit un message plus court, les balises <a/> disparaitront de son texte, et les possibles ancres-URLs perdront leur http://. Nous allons aussi fixer une limite à 3 liens maximum, il ne faut pas abuser…

Ce petit bout de code PHP filtre le contenu d’un commentaire juste avant qu’il ne soit enregistré en base de données. Si l’utilisateur n’est pas enregistré, alors on compte le nombre de mots, on déduit le quotas de liens autorisés et on supprime les balises <a/> au delà.

<?php
add_filter( 'preprocess_comment', 'willy_filter_links_in_comments' );
function willy_filter_links_in_comments( $commentdata ) {
	// bypass registred users
	if ( $commentdata['user_id'] ) {
		return $commentdata;
	}

	// Déduire le nombre de liens autorisés selon le nombre de mots
	$max = 3;
	$words_per_link = 50;
	$words = str_word_count( strip_tags( $commentdata['comment_content'] ) );
	$allowed_links = ( $max < $count = floor( $words / $words_per_link ) ) ? $max : $count;
    
	// Supprimer les lien sur `comment_author_url`
	if ( $allowed_links && ! empty( $commentdata['comment_author_url'] ) ) {
		$allowed_links--;
	} else {
		$commentdata['comment_author_url'] = false;
	}
	// La regex qui trouve les liens
	$re = '/<a[^>]*>([\s\S]*?)<\/a>/mi';
	// Supprimer les liens dans `comment_content`
	if ( preg_match_all( $re, $commentdata['comment_content'], $links )
	  && count( $links ) > $allowed_links ) {
	  	$commentdata['comment_content'] = preg_replace_callback( $re,
			function( $link ) use ( &$allowed_links ) {
				if ( $allowed_links ) {
					$allowed_links--;
					return $link[0];
				} else {
					return preg_replace( '/^https?:\/\//', '', $link[1] );
				}
			},
			$commentdata['comment_content']
		);
	}
	return $commentdata;
}

Vous pouvez bien sûr changer les variables $max et $words_per_link pour adapter les règles  de modération selon vos préférences.

Vos autres options de modérations en place resteront actives mais la suppression des liens auta lieu légèrement en amont.

Supprimer la possibilité de poster des liens sur les vieux articles

Les commentaires des articles ayant un peu d’ancienneté sont souvent un terrain propice au spam. Personnellement cela me gène de fermer complètement les commentaires, mais j’estime que le partage de lien sur un article de plus de 6 mois n’a pas d’intérêt (autre que le dépôt d’un backlink, 😉).

Je vous propose de compléter la fonction précédente avec une condition pour vérifier l’âge de l’article sur lequel est posté le commentaire. Ici, s’il a été publié il y a plus de six mois (6 * MONTH_IN_SECONDS), alors on fixe le quota de liens tolérés à 0.

<?php
/**
 * Filter links in comments
 */
add_filter( 'preprocess_comment', 'willy_filter_links_in_comments' );
function willy_filter_links_in_comments( $commentdata ) {
	// Ne pas filtrer les liens des utilisateurs enregistrés
	if ( $commentdata['user_id'] ) {
		return $commentdata;
	}

	// Vérifier la date
	$comment_post = get_post( intval( $commentdata['comment_post_ID'] ) );
	$date = ! empty( $commentdata['comment_date_gmt'] ) ? $commentdata['comment_date_gmt'] : current_time( 'mysql', 1 );
	$post_age = strtotime( $date ) - strtotime( $comment_post->post_date_gmt );
	// Si l’article est vieux, ne pas autoriser les liens
	if ( 6 * MONTH_IN_SECONDS > $post_age ) {
		$allowed_links = 0;
	} else {
		// Sinon, déduire le nombre de liens autorisés selon le nombre de mots
		$max = 3;
		$words_per_link = 50;
		$words = str_word_count( strip_tags( $commentdata['comment_content'] ) );
		$allowed_links = ( $max < $count = floor( $words / $words_per_link ) ) ? $max : $count;
	}

	// Supprimer les lien sur `comment_author_url`
	if ( $allowed_links && ! empty( $commentdata['comment_author_url'] ) ) {
		$allowed_links--;
	} else {
		$commentdata['comment_author_url'] = false;
	}

	// La regex qui trouve les liens
	$re = '/<a[^>]*>([\s\S]*?)<\/a>/mi';
	// Supprimer les liens dans `comment_content`
	if ( preg_match_all( $re, $commentdata['comment_content'], $links )
	  && count( $links ) > $allowed_links ) {
	  	$commentdata['comment_content'] = preg_replace_callback( $re,
			function( $link ) use ( &$allowed_links ) {
				if ( $allowed_links ) {
					$allowed_links--;
					return $link[0];
				} else {
					return preg_replace( '/^https?:\/\//', '', $link[1] );
				}
			},
			$commentdata['comment_content']
		);
	}

	return $commentdata;
}

J’ai écris cette petite astuce pour les besoins de mes sites, et je me suis dit que je pourrai vous en faire profiter. L’article explique donc comme cela fonctionne et donne des pistes pour comprendre comment intervenir sur la modification de commentaires. Mais, plutôt que de vous obliger à déposer ce code dans un plugin ou dans votre thème, je me suis dit que cela serait plus simple de vous fournir directement un plugin.

Le plugin Advanced Remove Links in Comments est donc disponible sur le répertoire officiel des extensions WordPress.

La base est identique avec le code ci-dessus, mais j’ai ajouté des options dans le menu « Réglages → Discussion » pour pouvoir changer les conditions de modération plus simplement. Les fonctions de l’extension sont aussi légèrement optimisées. Si ce plugin vous plait, n’hésitez pas à laisser un avis ou faire un don.

Voilà, j’espère que cette astuce vous aidera à modérer plus simplement vos commentaires, et vous permettra de comprendre un peu mieux comment il est possible d’utiliser les filtres du cœur de WordPress 🙂

À bientôt !

Contacter l'auteur :

willy bahuaud

Je suis Willy Bahuaud, développeur spécialiste de WordPress. Mon travail est de créer d’intervenir sur la partie « technique » des projets WordPress de mes clients. Je développe des extensions (espaces membres, géolocalisation, annuaires…) pour étendre les fonctionnalités d’un site au delà de ce que WordPress ou le thème en place ne le permettent. J'interviens aussi régulièrement sur la migration de contenus, l’optimisation de thème, la création de passerelles de données, l’adaptation de plugins premium et la création de sites .
Vous pouvez me contacter pour me faire part de vos projets.

4 commentaires

  1. Par Ludovic — Il y a 4 mois
    Je trouve ton idée très bonne pour éviter que les commentaires ne soient remplis de liens. En revanche, les liens contenus dans les commentaires ont un impact minime sur le SEO du site car WordPress leur ajoute automatiquement l’attribut rel="nofollow" ;)
  2. Par Willy Bahuaud — Il y a 4 mois
    Merci  !
    En fait les attributs nofollow permettent de ne pas transmettre de popularité aux pages ciblés par les liens. Ils ont donc été largement utilisés pour faire du « pagerank sculpting » (la popularité non transférée étant redistribuée sur les autres liens de la page). En 2009, et pour mettre fin à cette pratique, Google a décidé de ne plus redistribuer la popularité des liens en nofollow. Le « jus » part donc aux oubliettes…
    D’où mon envie de supprimer les liens inutiles 😛
  3. Par Amauri — Il y a 4 mois
    Sympa comme idée 🙂

    Ton exemple de commentaire m’en donne une autre:
    – filtrer les noms avec une liste de mots clés

    On voit beaucoup de « agence immobilière », « code promo », .. commenter et tenter d’avoir un lien ancré tout en ayant un commentaire qui passe entre les filtres.

    A moins que le fonction de liste noire de WP cherche aussi dans le nom?

  4. Par Loic — Il y a 4 mois
    Bonjour Willy,
    bravo pour tes conseils et plugins. Effectivement, j’en ai bien besoin car mon site est submergé de commentaires ( plus de 3500 en attente de modération!! !!) et j’ai beaucoup de mal et perte de temps pour les filtrer manuellement… d’autant plus que beaucoup sont des spams – certains provenant de sites chinois ou russes écrits en langue locale. Rien à voir avec mon site.
    Merci pour ton expérience partagée.
    Loic

Commenter