Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 49 additions & 14 deletions src/wp-admin/edit-form-comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,18 @@
<div class="misc-pub-section misc-pub-comment-status" id="comment-status">
<?php _e( 'Status:' ); ?> <span id="comment-status-display">
<?php
switch ( $comment->comment_approved ) {
case '1':
_e( 'Approved' );
break;
case '0':
_e( 'Pending' );
break;
case 'spam':
_e( 'Spam' );
break;
}
$comment_statuses = _wp_get_custom_comment_statuses();
$status_labels = array_merge(
$comment_statuses,
array(
'0' => _x( 'Pending', 'comment status' ),
'1' => _x( 'Approved', 'comment status' ),
'spam' => _x( 'Spam', 'comment status' ),
'trash' => _x( 'Trash', 'comment status' ),
)
);

echo esc_html( $status_labels[ $comment->comment_approved ] ?? $comment->comment_approved );
?>
</span>

Expand All @@ -133,9 +134,43 @@
_e( 'Comment status' );
?>
</legend>
<label><input type="radio"<?php checked( $comment->comment_approved, '1' ); ?> name="comment_status" value="1" /><?php _ex( 'Approved', 'comment status' ); ?></label><br />
<label><input type="radio"<?php checked( $comment->comment_approved, '0' ); ?> name="comment_status" value="0" /><?php _ex( 'Pending', 'comment status' ); ?></label><br />
<label><input type="radio"<?php checked( $comment->comment_approved, 'spam' ); ?> name="comment_status" value="spam" /><?php _ex( 'Spam', 'comment status' ); ?></label>
<?php
$comment_status_radio = array(
'1' => _x( 'Approved', 'comment status' ),
'0' => _x( 'Pending', 'comment status' ),
'spam' => _x( 'Spam', 'comment status' ),
);

foreach ( _wp_get_custom_comment_statuses() as $status => $label ) {
$comment_status_radio[ $status ] = $label;
}

/**
* Filters the editable comment statuses displayed on the edit comment screen.
*
* @since 7.1.0
*
* @param string[] $comment_status_radio List of editable comment status labels keyed by status.
* @param WP_Comment $comment Current comment object.
*/
$comment_status_radio = apply_filters( 'editable_comment_statuses', $comment_status_radio, $comment );

$valid_comment_status_radio = array_merge(
array(
'1' => true,
'0' => true,
'spam' => true,
),
array_fill_keys( array_keys( _wp_get_custom_comment_statuses() ), true )
);
$comment_status_radio = array_intersect_key( $comment_status_radio, $valid_comment_status_radio );

foreach ( $comment_status_radio as $status => $label ) :
?>
<label><input type="radio"<?php checked( $comment->comment_approved, $status ); ?> name="comment_status" value="<?php echo esc_attr( $status ); ?>" /><?php echo esc_html( $label ); ?></label><br />
<?php
endforeach;
?>
</fieldset>
</div><!-- .misc-pub-section -->

Expand Down
36 changes: 25 additions & 11 deletions src/wp-admin/includes/class-wp-comments-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,14 @@ public function prepare_items() {
$mode = get_user_setting( 'posts_list_mode', 'list' );
}

$comment_status = $_REQUEST['comment_status'] ?? 'all';
$comment_status = 'all';
if ( isset( $_REQUEST['comment_status'] ) && is_scalar( $_REQUEST['comment_status'] ) ) {
$comment_status = sanitize_key( wp_unslash( $_REQUEST['comment_status'] ) );
}

$valid_statuses = array_merge( array( 'all', 'mine', 'moderated', 'approved', 'spam', 'trash' ), array_keys( _wp_get_custom_comment_statuses() ) );

if ( ! in_array( $comment_status, array( 'all', 'mine', 'moderated', 'approved', 'spam', 'trash' ), true ) ) {
if ( ! in_array( $comment_status, $valid_statuses, true ) ) {
$comment_status = 'all';
}

Expand Down Expand Up @@ -301,6 +306,10 @@ protected function get_views() {
unset( $statuses['trash'] );
}

foreach ( _wp_get_custom_comment_statuses() as $status => $label ) {
$statuses[ $status ] = $label;
}

$link = admin_url( 'edit-comments.php' );

if ( ! empty( $comment_type ) && 'all' !== $comment_type ) {
Expand All @@ -324,7 +333,7 @@ protected function get_views() {
}

if ( ! isset( $num_comments->$status ) ) {
$num_comments->$status = 10;
$num_comments->$status = isset( _wp_get_custom_comment_statuses()[ $status ] ) ? 0 : 10;
}

$link = add_query_arg( 'comment_status', $status, $link );
Expand All @@ -339,16 +348,21 @@ protected function get_views() {
$link = add_query_arg( 's', esc_attr( wp_unslash( $_REQUEST['s'] ) ), $link );
*/

$count = sprintf(
'<span class="%s-count">%s</span>',
( 'moderated' === $status ) ? 'pending' : sanitize_html_class( $status ),
number_format_i18n( $num_comments->$status )
);

if ( is_array( $label ) ) {
$label = sprintf( translate_nooped_plural( $label, $num_comments->$status ), $count );
} else {
$label = sprintf( '%s <span class="count">(%s)</span>', esc_html( $label ), $count );
}

$status_links[ $status ] = array(
'url' => esc_url( $link ),
'label' => sprintf(
translate_nooped_plural( $label, $num_comments->$status ),
sprintf(
'<span class="%s-count">%s</span>',
( 'moderated' === $status ) ? 'pending' : $status,
number_format_i18n( $num_comments->$status )
)
),
'label' => $label,
'current' => $status === $comment_status,
);
}
Expand Down
16 changes: 14 additions & 2 deletions src/wp-admin/includes/comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,20 @@ function edit_comment() {
if ( isset( $_POST['newcomment_author_url'] ) ) {
$_POST['comment_author_url'] = $_POST['newcomment_author_url'];
}
if ( isset( $_POST['comment_status'] ) ) {
$_POST['comment_approved'] = $_POST['comment_status'];
if ( isset( $_POST['comment_status'] ) && is_scalar( $_POST['comment_status'] ) ) {
$comment_status = sanitize_key( wp_unslash( $_POST['comment_status'] ) );
$valid_comment_statuses = array_merge(
array(
'1' => true,
'0' => true,
'spam' => true,
),
array_fill_keys( array_keys( _wp_get_custom_comment_statuses() ), true )
);

if ( isset( $valid_comment_statuses[ $comment_status ] ) ) {
$_POST['comment_approved'] = $comment_status;
}
}
if ( isset( $_POST['content'] ) ) {
$_POST['comment_content'] = $_POST['content'];
Expand Down
4 changes: 3 additions & 1 deletion src/wp-includes/class-wp-comment-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,9 @@ protected function get_comment_ids() {

case 'all':
case '':
$status_clauses[] = "( comment_approved = '0' OR comment_approved = '1' )";
$all_statuses = array_merge( array( '0', '1' ), array_keys( _wp_get_custom_comment_statuses() ) );
$placeholders = implode( ', ', array_fill( 0, count( $all_statuses ), '%s' ) );
$status_clauses[] = $wpdb->prepare( "comment_approved IN ($placeholders)", $all_statuses );
break;

default:
Expand Down
11 changes: 9 additions & 2 deletions src/wp-includes/class-wp-xmlrpc-server.php
Original file line number Diff line number Diff line change
Expand Up @@ -3837,8 +3837,15 @@ public function wp_editComment( $args ) {
);

if ( isset( $content_struct['status'] ) ) {
$statuses = get_comment_statuses();
$statuses = array_keys( $statuses );
$statuses = array_merge(
array(
'hold',
'approve',
'spam',
'trash',
),
array_keys( _wp_get_custom_comment_statuses() )
);

if ( ! in_array( $content_struct['status'], $statuses, true ) ) {
return new IXR_Error( 401, __( 'Invalid comment status.' ) );
Expand Down
111 changes: 105 additions & 6 deletions src/wp-includes/comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,57 @@ function get_comment_statuses() {
'trash' => _x( 'Trash', 'comment status' ),
);

return $status;
/**
* Filters the list of supported comment statuses.
*
* The returned array is keyed by status and has translated status labels as values.
* Custom statuses are stored in the `comment_approved` database field using the
* array key as the raw status value. Custom status keys must be compatible with
* sanitize_key() and no longer than 20 characters.
*
* @since 7.1.0
*
* @param string[] $status List of comment status labels keyed by status.
*/
return apply_filters( 'comment_statuses', $status );
}

/**
* Retrieves registered custom comment statuses.
*
* @since 7.1.0
* @access private
*
* @return string[] List of valid custom comment status labels keyed by status.
* Invalid and reserved filtered statuses are excluded.
*/
function _wp_get_custom_comment_statuses() {
$reserved_statuses = array(
'0',
'1',
'all',
'any',
'approve',
'approved',
'hold',
'mine',
'moderated',
'post-trashed',
'spam',
'trash',
'unapproved',
'unspam',
'untrash',
);
$custom_statuses = array_diff_key( get_comment_statuses(), array_flip( $reserved_statuses ) );

foreach ( $custom_statuses as $status => $label ) {
if ( sanitize_key( $status ) !== $status || 20 < strlen( $status ) ) {
unset( $custom_statuses[ $status ] );
}
}

return $custom_statuses;
}

/**
Expand Down Expand Up @@ -400,7 +450,8 @@ function get_lastcommentmodified( $timezone = 'server' ) {
* @type int $trash The number of trashed comments.
* @type int $post-trashed The number of comments for posts that are in the trash.
* @type int $total_comments The total number of non-trashed comments, including spam.
* @type int $all The total number of pending or approved comments.
* @type int $all The total number of pending, approved, or custom status comments.
* @type int ...$custom_statuses The number of comments for each registered custom status.
* }
*/
function get_comment_count( $post_id = 0 ) {
Expand Down Expand Up @@ -436,7 +487,40 @@ function get_comment_count( $post_id = 0 ) {
$comment_count[ $key ] = get_comments( array_merge( $args, array( 'status' => $value ) ) );
}

$comment_count['all'] = $comment_count['approved'] + $comment_count['awaiting_moderation'];
$custom_statuses = _wp_get_custom_comment_statuses();
foreach ( $custom_statuses as $status => $label ) {
$comment_count[ $status ] = 0;
}

if ( $custom_statuses ) {
global $wpdb;

$custom_status_placeholders = implode( ', ', array_fill( 0, count( $custom_statuses ), '%s' ) );
$custom_status_args = array_keys( $custom_statuses );
$post_id_sql = '';

if ( $post_id > 0 ) {
$post_id_sql = ' AND comment_post_ID = %d';
$custom_status_args[] = $post_id;
}

$custom_status_counts = $wpdb->get_results(
$wpdb->prepare(
"SELECT comment_approved, COUNT(*) AS num_comments FROM $wpdb->comments WHERE comment_approved IN ($custom_status_placeholders)$post_id_sql GROUP BY comment_approved",
$custom_status_args
),
OBJECT_K
);

foreach ( $custom_status_counts as $status => $row ) {
$comment_count[ $status ] = (int) $row->num_comments;
}
}

$comment_count['all'] = $comment_count['approved'] + $comment_count['awaiting_moderation'];
foreach ( array_keys( $custom_statuses ) as $status ) {
$comment_count['all'] += $comment_count[ $status ];
}
$comment_count['total_comments'] = $comment_count['all'] + $comment_count['spam'];

return array_map( 'intval', $comment_count );
Expand Down Expand Up @@ -1825,7 +1909,8 @@ function wp_unspam_comment( $comment_id ) {
* @since 1.0.0
*
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object
* @return string|false Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
* @return string|false Status might be 'trash', 'approved', 'unapproved', 'spam', or a custom status.
* False on failure.
*/
function wp_get_comment_status( $comment_id ) {
$comment = get_comment( $comment_id );
Expand All @@ -1845,6 +1930,8 @@ function wp_get_comment_status( $comment_id ) {
return 'spam';
} elseif ( 'trash' === $approved ) {
return 'trash';
} elseif ( isset( _wp_get_custom_comment_statuses()[ $approved ] ) ) {
return $approved;
} else {
return false;
}
Expand Down Expand Up @@ -2529,7 +2616,8 @@ function wp_new_comment_via_rest_notify_postauthor( $comment ) {
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
* @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
* @param string $comment_status New comment status, either 'hold', 'approve', 'spam', 'trash',
* or a custom status from get_comment_statuses().
* @param bool $wp_error Whether to return a WP_Error object if there is a failure. Default false.
* @return bool|WP_Error True on success, false or WP_Error on failure.
*/
Expand All @@ -2553,7 +2641,18 @@ function wp_set_comment_status( $comment_id, $comment_status, $wp_error = false
$status = 'trash';
break;
default:
return false;
if ( ! is_scalar( $comment_status ) ) {
return false;
}

$comment_status = sanitize_key( (string) $comment_status );

if ( ! isset( _wp_get_custom_comment_statuses()[ $comment_status ] ) ) {
return false;
}

$status = $comment_status;
break;
}

$comment_old = clone get_comment( $comment_id );
Expand Down
Loading
Loading