Comments: Abstract `die()` calls from comment submission routine.
Since 4.4, comment submission has been mostly abstracted into a function, rather than being processed inline in wp-comments-post.php. This change made it easier to write automated tests against the bulk of the comment submission process. `wp_allow_comment()` remained untestable, however: when a comment failed one of its checks (flooding, duplicates, etc), `die()` or `wp_die()` would be called directly. This shortcoming posed problems for any application attempting to use WP's comment verification functions in an abstract way - from PHPUnit to the REST API. The current changeset introduces a new parameter, `$avoid_die`, to the `wp_new_comment()` stack. When set to `true`, `wp_new_comment()` and `wp_allow_comment()` will return `WP_Error` objects when a comment check fails. When set to `false` - the default, for backward compatibility - a failed check will result in a `die()` or `wp_die()`, as appropriate. Prior to this changeset, default comment flood checks took place in the function `check_comment_flood_db()`, which was hooked to the 'check_comment_flood' action. This design allowed the default comment flood routine to be bypassed or replaced using `remove_action()`. In order to maintain backward compatibility with this usage, while simultaneously converting the comment flood logic into something that returns a value rather than calling `die()` directly, `check_comment_flood_db()` has been changed into a wrapper function for a call to `add_filter()`; this, in turn, adds the *actual* comment flood check to a new filter, 'wp_is_comment_flood'. Note that direct calls to `check_comment_flood_db()` will no longer do anything in isolation. Props websupporter, rachelbaker. Fixes #36901. Built from https://develop.svn.wordpress.org/trunk@38778 git-svn-id: http://core.svn.wordpress.org/trunk@38721 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
f40c2a62a6
commit
0bdfa2ab1e
|
@ -588,13 +588,19 @@ function sanitize_comment_cookies() {
|
||||||
* Validates whether this comment is allowed to be made.
|
* Validates whether this comment is allowed to be made.
|
||||||
*
|
*
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
|
* @since 4.7.0 The `$avoid_die` parameter was added, allowing the function to
|
||||||
|
* return a WP_Error object instead of dying.
|
||||||
*
|
*
|
||||||
* @global wpdb $wpdb WordPress database abstraction object.
|
* @global wpdb $wpdb WordPress database abstraction object.
|
||||||
*
|
*
|
||||||
* @param array $commentdata Contains information on the comment
|
* @param array $commentdata Contains information on the comment.
|
||||||
* @return int|string Signifies the approval status (0|1|'spam')
|
* @param bool $avoid_die When true, a disallowed comment will result in the function
|
||||||
|
* returning a WP_Error object, rather than executing wp_die().
|
||||||
|
* Default false.
|
||||||
|
* @return int|string|WP_Error Allowed comments return the approval status (0|1|'spam').
|
||||||
|
* If `$avoid_die` is true, disallowed comments return a WP_Error.
|
||||||
*/
|
*/
|
||||||
function wp_allow_comment( $commentdata ) {
|
function wp_allow_comment( $commentdata, $avoid_die = false ) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
// Simple duplicate check
|
// Simple duplicate check
|
||||||
|
@ -639,11 +645,16 @@ function wp_allow_comment( $commentdata ) {
|
||||||
* @param array $commentdata Comment data.
|
* @param array $commentdata Comment data.
|
||||||
*/
|
*/
|
||||||
do_action( 'comment_duplicate_trigger', $commentdata );
|
do_action( 'comment_duplicate_trigger', $commentdata );
|
||||||
|
if ( true === $avoid_die ) {
|
||||||
|
return new WP_Error( 'comment_duplicate', __( 'Duplicate comment detected; it looks as though you’ve already said that!' ), $dupe_id );
|
||||||
|
} else {
|
||||||
if ( wp_doing_ajax() ) {
|
if ( wp_doing_ajax() ) {
|
||||||
die( __('Duplicate comment detected; it looks as though you’ve already said that!') );
|
die( __('Duplicate comment detected; it looks as though you’ve already said that!') );
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_die( __( 'Duplicate comment detected; it looks as though you’ve already said that!' ), 409 );
|
wp_die( __( 'Duplicate comment detected; it looks as though you’ve already said that!' ), 409 );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires immediately before a comment is marked approved.
|
* Fires immediately before a comment is marked approved.
|
||||||
|
@ -651,18 +662,49 @@ function wp_allow_comment( $commentdata ) {
|
||||||
* Allows checking for comment flooding.
|
* Allows checking for comment flooding.
|
||||||
*
|
*
|
||||||
* @since 2.3.0
|
* @since 2.3.0
|
||||||
|
* @since 4.7.0 The `$avoid_die` parameter was added.
|
||||||
*
|
*
|
||||||
* @param string $comment_author_IP Comment author's IP address.
|
* @param string $comment_author_IP Comment author's IP address.
|
||||||
* @param string $comment_author_email Comment author's email.
|
* @param string $comment_author_email Comment author's email.
|
||||||
* @param string $comment_date_gmt GMT date the comment was posted.
|
* @param string $comment_date_gmt GMT date the comment was posted.
|
||||||
|
* @param bool $avoid_die Whether to prevent executing wp_die()
|
||||||
|
* or die() if a comment flood is occurring.
|
||||||
*/
|
*/
|
||||||
do_action(
|
do_action(
|
||||||
'check_comment_flood',
|
'check_comment_flood',
|
||||||
$commentdata['comment_author_IP'],
|
$commentdata['comment_author_IP'],
|
||||||
$commentdata['comment_author_email'],
|
$commentdata['comment_author_email'],
|
||||||
$commentdata['comment_date_gmt']
|
$commentdata['comment_date_gmt'],
|
||||||
|
$avoid_die
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters whether a comment is part of a comment flood.
|
||||||
|
*
|
||||||
|
* The default check is wp_check_comment_flood(). See check_comment_flood_db().
|
||||||
|
*
|
||||||
|
* @since 4.7.0
|
||||||
|
*
|
||||||
|
* @param bool $is_flood Is a comment flooding occurring? Default false.
|
||||||
|
* @param string $comment_author_IP Comment author's IP address.
|
||||||
|
* @param string $comment_author_email Comment author's email.
|
||||||
|
* @param string $comment_date_gmt GMT date the comment was posted.
|
||||||
|
* @param bool $avoid_die Whether to prevent executing wp_die()
|
||||||
|
* or die() if a comment flood is occurring.
|
||||||
|
*/
|
||||||
|
$is_flood = apply_filters(
|
||||||
|
'wp_is_comment_flood',
|
||||||
|
false,
|
||||||
|
$commentdata['comment_author_IP'],
|
||||||
|
$commentdata['comment_author_email'],
|
||||||
|
$commentdata['comment_date_gmt'],
|
||||||
|
$avoid_die
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $is_flood ) {
|
||||||
|
return new WP_Error( 'comment_flood', __( 'You are posting comments too quickly. Slow down.' ) );
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! empty( $commentdata['user_id'] ) ) {
|
if ( ! empty( $commentdata['user_id'] ) ) {
|
||||||
$user = get_userdata( $commentdata['user_id'] );
|
$user = get_userdata( $commentdata['user_id'] );
|
||||||
$post_author = $wpdb->get_var( $wpdb->prepare(
|
$post_author = $wpdb->get_var( $wpdb->prepare(
|
||||||
|
@ -715,24 +757,50 @@ function wp_allow_comment( $commentdata ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether comment flooding is occurring.
|
* Hooks WP's native database-based comment-flood check.
|
||||||
|
*
|
||||||
|
* This wrapper maintains backward compatibility with plugins that expect to
|
||||||
|
* be able to unhook the legacy check_comment_flood_db() function from
|
||||||
|
* 'check_comment_flood' using remove_action().
|
||||||
|
*
|
||||||
|
* @since 2.3.0
|
||||||
|
* @since 4.7.0 Converted to be an add_filter() wrapper.
|
||||||
|
*/
|
||||||
|
function check_comment_flood_db() {
|
||||||
|
add_filter( 'wp_is_comment_flood', 'wp_check_comment_flood', 10, 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether comment flooding is occurring.
|
||||||
*
|
*
|
||||||
* Won't run, if current user can manage options, so to not block
|
* Won't run, if current user can manage options, so to not block
|
||||||
* administrators.
|
* administrators.
|
||||||
*
|
*
|
||||||
* @since 2.3.0
|
* @since 4.7.0
|
||||||
*
|
*
|
||||||
* @global wpdb $wpdb WordPress database abstraction object.
|
* @global wpdb $wpdb WordPress database abstraction object.
|
||||||
*
|
*
|
||||||
|
* @param bool $is_flood Is a comment flooding occurring?
|
||||||
* @param string $ip Comment IP.
|
* @param string $ip Comment IP.
|
||||||
* @param string $email Comment author email address.
|
* @param string $email Comment author email address.
|
||||||
* @param string $date MySQL time string.
|
* @param string $date MySQL time string.
|
||||||
|
* @param bool $avoid_die When true, a disallowed comment will result in the function
|
||||||
|
* returning a WP_Error object, rather than executing wp_die().
|
||||||
|
* Default false.
|
||||||
|
* @return bool Whether comment flooding is occurring.
|
||||||
*/
|
*/
|
||||||
function check_comment_flood_db( $ip, $email, $date ) {
|
function wp_check_comment_flood( $is_flood, $ip, $email, $date, $avoid_die = false ) {
|
||||||
|
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
|
// Another callback has declared a flood. Trust it.
|
||||||
|
if ( true === $is_flood ) {
|
||||||
|
return $is_flood;
|
||||||
|
}
|
||||||
|
|
||||||
// don't throttle admins or moderators
|
// don't throttle admins or moderators
|
||||||
if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
|
if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
|
$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
|
||||||
|
|
||||||
|
@ -774,15 +842,21 @@ function check_comment_flood_db( $ip, $email, $date ) {
|
||||||
* @param int $time_newcomment Timestamp of when the new comment was posted.
|
* @param int $time_newcomment Timestamp of when the new comment was posted.
|
||||||
*/
|
*/
|
||||||
do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
|
do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
|
||||||
|
if ( true === $avoid_die ) {
|
||||||
if ( wp_doing_ajax() )
|
return true;
|
||||||
|
} else {
|
||||||
|
if ( wp_doing_ajax() ) {
|
||||||
die( __('You are posting comments too quickly. Slow down.') );
|
die( __('You are posting comments too quickly. Slow down.') );
|
||||||
|
}
|
||||||
|
|
||||||
wp_die( __( 'You are posting comments too quickly. Slow down.' ), 429 );
|
wp_die( __( 'You are posting comments too quickly. Slow down.' ), 429 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Separates an array of comments into an array keyed by comment_type.
|
* Separates an array of comments into an array keyed by comment_type.
|
||||||
*
|
*
|
||||||
|
@ -1730,6 +1804,8 @@ function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment)
|
||||||
*
|
*
|
||||||
* @since 1.5.0
|
* @since 1.5.0
|
||||||
* @since 4.3.0 'comment_agent' and 'comment_author_IP' can be set via `$commentdata`.
|
* @since 4.3.0 'comment_agent' and 'comment_author_IP' can be set via `$commentdata`.
|
||||||
|
* @since 4.7.0 The `$avoid_die` parameter was added, allowing the function to
|
||||||
|
* return a WP_Error object instead of dying.
|
||||||
*
|
*
|
||||||
* @see wp_insert_comment()
|
* @see wp_insert_comment()
|
||||||
* @global wpdb $wpdb WordPress database abstraction object.
|
* @global wpdb $wpdb WordPress database abstraction object.
|
||||||
|
@ -1753,9 +1829,11 @@ function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment)
|
||||||
* @type string $comment_author_IP Comment author IP address in IPv4 format. Default is the value of
|
* @type string $comment_author_IP Comment author IP address in IPv4 format. Default is the value of
|
||||||
* 'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
|
* 'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
|
||||||
* }
|
* }
|
||||||
* @return int|false The ID of the comment on success, false on failure.
|
* @param bool $avoid_die Should errors be returned as WP_Error objects instead of
|
||||||
|
* executing wp_die()? Default false.
|
||||||
|
* @return int|false|WP_Error The ID of the comment on success, false or WP_Error on failure.
|
||||||
*/
|
*/
|
||||||
function wp_new_comment( $commentdata ) {
|
function wp_new_comment( $commentdata, $avoid_die = false ) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
if ( isset( $commentdata['user_ID'] ) ) {
|
if ( isset( $commentdata['user_ID'] ) ) {
|
||||||
|
@ -1804,7 +1882,10 @@ function wp_new_comment( $commentdata ) {
|
||||||
|
|
||||||
$commentdata = wp_filter_comment($commentdata);
|
$commentdata = wp_filter_comment($commentdata);
|
||||||
|
|
||||||
$commentdata['comment_approved'] = wp_allow_comment($commentdata);
|
$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
|
||||||
|
if ( is_wp_error( $commentdata['comment_approved'] ) ) {
|
||||||
|
return $commentdata['comment_approved'];
|
||||||
|
}
|
||||||
|
|
||||||
$comment_ID = wp_insert_comment($commentdata);
|
$comment_ID = wp_insert_comment($commentdata);
|
||||||
if ( ! $comment_ID ) {
|
if ( ! $comment_ID ) {
|
||||||
|
@ -1818,7 +1899,10 @@ function wp_new_comment( $commentdata ) {
|
||||||
|
|
||||||
$commentdata = wp_filter_comment( $commentdata );
|
$commentdata = wp_filter_comment( $commentdata );
|
||||||
|
|
||||||
$commentdata['comment_approved'] = wp_allow_comment( $commentdata );
|
$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
|
||||||
|
if ( is_wp_error( $commentdata['comment_approved'] ) ) {
|
||||||
|
return $commentdata['comment_approved'];
|
||||||
|
}
|
||||||
|
|
||||||
$comment_ID = wp_insert_comment( $commentdata );
|
$comment_ID = wp_insert_comment( $commentdata );
|
||||||
if ( ! $comment_ID ) {
|
if ( ! $comment_ID ) {
|
||||||
|
@ -2940,11 +3024,14 @@ function wp_handle_comment_submission( $comment_data ) {
|
||||||
'user_ID'
|
'user_ID'
|
||||||
);
|
);
|
||||||
|
|
||||||
$comment_id = wp_new_comment( wp_slash( $commentdata ) );
|
$comment_id = wp_new_comment( wp_slash( $commentdata ), true );
|
||||||
|
if ( is_wp_error( $comment_id ) ) {
|
||||||
|
return $comment_id;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! $comment_id ) {
|
if ( ! $comment_id ) {
|
||||||
return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
|
return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_comment( $comment_id );
|
return get_comment( $comment_id );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,7 +197,7 @@ add_filter( 'tiny_mce_before_init', '_mce_set_direction' );
|
||||||
add_filter( 'teeny_mce_before_init', '_mce_set_direction' );
|
add_filter( 'teeny_mce_before_init', '_mce_set_direction' );
|
||||||
add_filter( 'pre_kses', 'wp_pre_kses_less_than' );
|
add_filter( 'pre_kses', 'wp_pre_kses_less_than' );
|
||||||
add_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 );
|
add_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 );
|
||||||
add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 3 );
|
add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
|
||||||
add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood', 10, 3 );
|
add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood', 10, 3 );
|
||||||
add_filter( 'pre_comment_content', 'wp_rel_nofollow', 15 );
|
add_filter( 'pre_comment_content', 'wp_rel_nofollow', 15 );
|
||||||
add_filter( 'comment_email', 'antispambot' );
|
add_filter( 'comment_email', 'antispambot' );
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '4.7-alpha-38777';
|
$wp_version = '4.7-alpha-38778';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
Loading…
Reference in New Issue