Make WordPress Core

Opened 4 years ago

Last modified 12 months ago

#49869 new defect (bug)

Apply comment field filters to backend

Reported by: ttodua's profile ttodua Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Comments Keywords:
Focuses: Cc:

Description

Recently, I had to work on an internally consuming WP project. I am a bit surprised how WP filters are mainly affecting only visual side, instead of applying to backend functions.

so, for example:

add_filter('comment_form_default_fields', 'website_remove');
function website_remove($fields)
{
	if( isset($fields['url']) )
		unset($fields['url']);
	return $fields;
}

it only removes 'url' input field from output of comment form. So, what is the point of that, if it can be simply achieved by css display:none. ? the intention is clear, that it should REMOVE "url" parameter from comment system at all.
However, at this moment, even if people use 'comment_form_default_fields' filter to remove url, it is almost meaningless - anyone in front-end form can just insert url field (i mainly say bots, but also typical user can just insert "url" parameter in browser "inspect element") and submit form and in backend, in wp-includes/comment.php :: wp_handle_comment_submission still accepts the url field.

In parallel of the fact that WP advocates "never trust user input", the filters should be applied firstly and mostly to backend functions in my mind. I firmly reckon that the filters (in any other WP form too) should be applied in both front-end and back-end functions for same parameter.

So in backend, the same filter should be applied to comment fields ( in wp-includes/comment.php :: wp_handle_comment_submission):

$comment_data = apply_filters('comment_form_default_fields', $comment_data, true);

the third parameter is indication whether the filter is in BACK-END (true) or FRONT-END (false).
So, in front-end output of comments (wp-includes\comment-template.php, function comment_form) the filter can now be:

<?php
$fields = apply_filters( 'comment_form_default_fields', $fields, false );

instead of

<?php
$fields = apply_filters( 'comment_form_default_fields', $fields);

Hope you understand my concern. Every filter for fields should affect two places - output and input.

Attachments (1)

49869.patch (1.4 KB) - added by ttodua 4 years ago.

Download all attachments as: .zip

Change History (4)

@ttodua
4 years ago

#1 @SergeyBiryukov
4 years ago

  • Component changed from General to Comments

#2 @ttodua
4 years ago

Moreover, if WP was more object-oriented in full details, there should have been the 3rd place where the same hook should be applied - to EXISTING DATA.
So, ideally:

-in output (during comment-form):

$output_fields  = apply_filters('comment_form_default_fields', $fields, "is_frontend");

-in backend (during save):

$output_fields  = apply_filters('comment_form_default_fields', $fields, "is_backend");

-in getting the existing data (i.e. in function "get_comment_author_link"):

$existing_fields= apply_filters('comment_form_default_fields', $fields, "is_existing");

#3 @bonjour52
12 months ago

Hello,

I've checked the top Internet search results for removing the comment author URL, as well as the top WordPress plugins for achieving the same goal. They all rely exclusively on the comment_form_default_fields filter, which, as you argued correctly, is bypassed and mocked by bots. Instead of using comment fields, bots actually use POST request fields to action wp-comments-post.php: they couldn't care less which comment fields are hidden, and which ones are shown.

Now, after browsing WordPress' code, I stumbled on filter preprocess_comment:

"Filters a comment’s data before it is sanitized and inserted into the database."
https://developer.wordpress.org/reference/hooks/preprocess_comment/

This was a revelation, honnestly! I think that, as long as people realize that preprocess_comment is available, it is a perfectly robust solution. It's just that the top references on the Internet seem to either ignore the existance of preprocess_comment or being very naive about what comment_form_default_fields does.

Anyway, I ended up writing the following code snippet for my site, which blocks comments with non-empty author URL (since I wrote it for myself, it is in French):

<?php
function verifier_commentaire( $donnees_commentaire ) {
        if( !empty( $donnees_commentaire['comment_author_url'] ) ) {
                wp_die( '<strong>ERREUR</strong> : Le message d’erreur.', 'Le titre', array( 'response' => 403 ) );
        }
        return $donnees_commentaire;
}
add_filter( 'preprocess_comment', 'verifier_commentaire' );

Finally, here is a debug test code I used for posting a comment from a bot's perspective. Test first by including the 'url'=>… line, and then by removing it.

<?php
$app = curl_init();
curl_setopt( $app, CURLOPT_URL,"https://www.test.com/wp-comments-post.php" );
curl_setopt( $app, CURLOPT_POST, 1 );
curl_setopt( $app, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $app, CURLOPT_FOLLOWLOCATION, 1 );
curl_setopt( $app, CURLOPT_SSL_VERIFYPEER, 0 );
$donnees = array(
    'comment_post_ID'=>14259,
    'author'=>'Nom d’auteur',
    'email'=>'adresse@auteur.com',
    'url'=>'https://www.auteur.net',
    'comment'=>'Texte du commentaire',
    'submit'=>'Envoyer'
);
curl_setopt( $app, CURLOPT_POSTFIELDS, $donnees );
$resultat = curl_exec( $app );
curl_close( $app );
echo "RÉSULTAT : " . $resultat;

Note: See TracTickets for help on using tickets.