: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( ( ! $comments || ! is_array( $comments ) ) && ! empty( $wp_query->comments ) ) {
$comments = $wp_query->comments;
if ( empty( $comments ) ) {
if ( ! get_option( 'page_comments' ) ) {
if ( ! isset( $per_page ) ) {
$per_page = (int) get_query_var( 'comments_per_page' );
$per_page = (int) get_option( 'comments_per_page' );
if ( ! isset( $threaded ) ) {
$threaded = get_option( 'thread_comments' );
$walker = new Walker_Comment();
$count = ceil( $walker->get_number_of_root_elements( $comments ) / $per_page );
$count = ceil( count( $comments ) / $per_page );
* Calculates what page number a comment will appear on for comment paging.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int $comment_id Comment ID.
* Array of optional arguments.
* @type string $type Limit paginated comments to those matching a given type.
* Accepts 'comment', 'trackback', 'pingback', 'pings'
* (trackbacks and pingbacks), or 'all'. Default 'all'.
* @type int $per_page Per-page count to use when calculating pagination.
* Defaults to the value of the 'comments_per_page' option.
* @type int|string $max_depth If greater than 1, comment page will be determined
* for the top-level parent `$comment_id`.
* Defaults to the value of the 'thread_comments_depth' option.
* @return int|null Comment page number or null on error.
function get_page_of_comment( $comment_id, $args = array() ) {
$comment = get_comment( $comment_id );
$args = wp_parse_args( $args, $defaults );
// Order of precedence: 1. `$args['per_page']`, 2. 'comments_per_page' query_var, 3. 'comments_per_page' option.
if ( get_option( 'page_comments' ) ) {
if ( '' === $args['per_page'] ) {
$args['per_page'] = get_query_var( 'comments_per_page' );
if ( '' === $args['per_page'] ) {
$args['per_page'] = get_option( 'comments_per_page' );
if ( empty( $args['per_page'] ) ) {
if ( $args['per_page'] < 1 ) {
if ( '' === $args['max_depth'] ) {
if ( get_option( 'thread_comments' ) ) {
$args['max_depth'] = get_option( 'thread_comments_depth' );
// Find this comment's top-level parent if threading is enabled.
if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent ) {
return get_page_of_comment( $comment->comment_parent, $args );
'post_id' => $comment->comment_post_ID,
'column' => "$wpdb->comments.comment_date_gmt",
'before' => $comment->comment_date_gmt,
if ( is_user_logged_in() ) {
$comment_args['include_unapproved'] = array( get_current_user_id() );
$unapproved_email = wp_get_unapproved_comment_author_email();
if ( $unapproved_email ) {
$comment_args['include_unapproved'] = array( $unapproved_email );
* Filters the arguments used to query comments in get_page_of_comment().
* @see WP_Comment_Query::__construct()
* @param array $comment_args {
* Array of WP_Comment_Query arguments.
* @type string $type Limit paginated comments to those matching a given type.
* Accepts 'comment', 'trackback', 'pingback', 'pings'
* (trackbacks and pingbacks), or 'all'. Default 'all'.
* @type int $post_id ID of the post.
* @type string $fields Comment fields to return.
* @type bool $count Whether to return a comment count (true) or array
* of comment objects (false).
* @type string $status Comment status.
* @type int $parent Parent ID of comment to retrieve children of.
* @type array $date_query Date query clauses to limit comments by. See WP_Date_Query.
* @type array $include_unapproved Array of IDs or email addresses whose unapproved comments
* will be included in paginated comments.
$comment_args = apply_filters( 'get_page_of_comment_query_args', $comment_args );
$comment_query = new WP_Comment_Query();
$older_comment_count = $comment_query->query( $comment_args );
// No older comments? Then it's page #1.
if ( 0 == $older_comment_count ) {
// Divide comments older than this one by comments per page to get this comment's page number.
$page = (int) ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
* Filters the calculated page on which a comment appears.
* @since 4.7.0 Introduced the `$comment_id` parameter.
* @param int $page Comment page.
* Arguments used to calculate pagination. These include arguments auto-detected by the function,
* based on query vars, system settings, etc. For pristine arguments passed to the function,
* @type string $type Type of comments to count.
* @type int $page Calculated current page.
* @type int $per_page Calculated number of comments per page.
* @type int $max_depth Maximum comment threading depth allowed.
* @param array $original_args {
* Array of arguments passed to the function. Some or all of these may not be set.
* @type string $type Type of comments to count.
* @type int $page Current comment page.
* @type int $per_page Number of comments per page.
* @type int $max_depth Maximum comment threading depth allowed.
* @param int $comment_id ID of the comment.
return apply_filters( 'get_page_of_comment', (int) $page, $args, $original_args, $comment_id );
* Retrieves the maximum character lengths for the comment form fields.
* @global wpdb $wpdb WordPress database abstraction object.
* @return int[] Array of maximum lengths keyed by field name.
function wp_get_comment_fields_max_lengths() {
'comment_author_email' => 100,
'comment_author_url' => 200,
'comment_content' => 65525,
foreach ( $lengths as $column => $length ) {
$col_length = $wpdb->get_col_length( $wpdb->comments, $column );
// No point if we can't get the DB column lengths.
if ( is_wp_error( $col_length ) ) {
if ( ! is_array( $col_length ) && (int) $col_length > 0 ) {
$max_length = (int) $col_length;
} elseif ( is_array( $col_length ) && isset( $col_length['length'] ) && (int) $col_length['length'] > 0 ) {
$max_length = (int) $col_length['length'];
if ( ! empty( $col_length['type'] ) && 'byte' === $col_length['type'] ) {
$max_length = $max_length - 10;
$lengths[ $column ] = $max_length;
* Filters the lengths for the comment form fields.
* @param int[] $lengths Array of maximum lengths keyed by field name.
return apply_filters( 'wp_get_comment_fields_max_lengths', $lengths );
* Compares the lengths of comment data against the maximum character limits.
* @param array $comment_data Array of arguments for inserting a comment.
* @return WP_Error|true WP_Error when a comment field exceeds the limit,
function wp_check_comment_data_max_lengths( $comment_data ) {
$max_lengths = wp_get_comment_fields_max_lengths();
if ( isset( $comment_data['comment_author'] ) && mb_strlen( $comment_data['comment_author'], '8bit' ) > $max_lengths['comment_author'] ) {
return new WP_Error( 'comment_author_column_length', __( '<strong>Error:</strong> Your name is too long.' ), 200 );
if ( isset( $comment_data['comment_author_email'] ) && strlen( $comment_data['comment_author_email'] ) > $max_lengths['comment_author_email'] ) {
return new WP_Error( 'comment_author_email_column_length', __( '<strong>Error:</strong> Your email address is too long.' ), 200 );
if ( isset( $comment_data['comment_author_url'] ) && strlen( $comment_data['comment_author_url'] ) > $max_lengths['comment_author_url'] ) {
return new WP_Error( 'comment_author_url_column_length', __( '<strong>Error:</strong> Your URL is too long.' ), 200 );
if ( isset( $comment_data['comment_content'] ) && mb_strlen( $comment_data['comment_content'], '8bit' ) > $max_lengths['comment_content'] ) {
return new WP_Error( 'comment_content_column_length', __( '<strong>Error:</strong> Your comment is too long.' ), 200 );
* Checks if a comment contains disallowed characters or words.
* @param string $author The author of the comment
* @param string $email The email of the comment
* @param string $url The url used in the comment
* @param string $comment The comment content
* @param string $user_ip The comment author's IP address
* @param string $user_agent The author's browser user agent
* @return bool True if comment contains disallowed content, false if comment does not
function wp_check_comment_disallowed_list( $author, $email, $url, $comment, $user_ip, $user_agent ) {
* Fires before the comment is tested for disallowed characters or words.
* @deprecated 5.5.0 Use {@see 'wp_check_comment_disallowed_list'} instead.
* @param string $author Comment author.
* @param string $email Comment author's email.
* @param string $url Comment author's URL.
* @param string $comment Comment content.
* @param string $user_ip Comment author's IP address.
* @param string $user_agent Comment author's browser user agent.
array( $author, $email, $url, $comment, $user_ip, $user_agent ),
'wp_check_comment_disallowed_list',
__( 'Please consider writing more inclusive code.' )
* Fires before the comment is tested for disallowed characters or words.
* @param string $author Comment author.
* @param string $email Comment author's email.
* @param string $url Comment author's URL.
* @param string $comment Comment content.
* @param string $user_ip Comment author's IP address.
* @param string $user_agent Comment author's browser user agent.
do_action( 'wp_check_comment_disallowed_list', $author, $email, $url, $comment, $user_ip, $user_agent );
$mod_keys = trim( get_option( 'disallowed_keys' ) );
if ( '' === $mod_keys ) {
return false; // If moderation keys are empty.
// Ensure HTML tags are not being used to bypass the list of disallowed characters and words.
$comment_without_html = wp_strip_all_tags( $comment );
$words = explode( "\n", $mod_keys );
foreach ( (array) $words as $word ) {
// Do some escaping magic so that '#' chars in the spam words don't break things:
$word = preg_quote( $word, '#' );
if ( preg_match( $pattern, $author )
|| preg_match( $pattern, $email )
|| preg_match( $pattern, $url )
|| preg_match( $pattern, $comment )
|| preg_match( $pattern, $comment_without_html )
|| preg_match( $pattern, $user_ip )
|| preg_match( $pattern, $user_agent )
* Retrieves the total comment counts for the whole site or a single post.
* The comment stats are cached and then retrieved, if they already exist in the
* @see get_comment_count() Which handles fetching the live comment counts.
* @param int $post_id Optional. Restrict the comment counts to the given post. Default 0, which indicates that
* comment counts for the whole site will be retrieved.
* The number of comments keyed by their status.
* @type int $approved The number of approved comments.
* @type int $moderated The number of comments awaiting moderation (a.k.a. pending).
* @type int $spam The number of spam comments.
* @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.
function wp_count_comments( $post_id = 0 ) {
$post_id = (int) $post_id;
* Filters the comments count for a given post or the whole site.
* @param array|stdClass $count An empty array or an object containing comment counts.
* @param int $post_id The post ID. Can be 0 to represent the whole site.
$filtered = apply_filters( 'wp_count_comments', array(), $post_id );
if ( ! empty( $filtered ) ) {
$count = wp_cache_get( "comments-{$post_id}", 'counts' );
if ( false !== $count ) {
$stats = get_comment_count( $post_id );
$stats['moderated'] = $stats['awaiting_moderation'];
unset( $stats['awaiting_moderation'] );
$stats_object = (object) $stats;
wp_cache_set( "comments-{$post_id}", $stats_object, 'counts' );
* Trashes or deletes a comment.
* The comment is moved to Trash instead of permanently deleted unless Trash is
* disabled, item is already in the Trash, or $force_delete is true.
* The post comment count will be updated if the comment was approved and has a
* @global wpdb $wpdb WordPress database abstraction object.
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
* @param bool $force_delete Whether to bypass Trash and force deletion. Default false.
* @return bool True on success, false on failure.
function wp_delete_comment( $comment_id, $force_delete = false ) {
$comment = get_comment( $comment_id );
if ( ! $force_delete && EMPTY_TRASH_DAYS && ! in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ), true ) ) {
return wp_trash_comment( $comment_id );
* Fires immediately before a comment is deleted from the database.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The comment to be deleted.
do_action( 'delete_comment', $comment->comment_ID, $comment );
// Move children up a level.
$children = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment->comment_ID ) );
if ( ! empty( $children ) ) {
$wpdb->update( $wpdb->comments, array( 'comment_parent' => $comment->comment_parent ), array( 'comment_parent' => $comment->comment_ID ) );
clean_comment_cache( $children );
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
foreach ( $meta_ids as $mid ) {
delete_metadata_by_mid( 'comment', $mid );
if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment->comment_ID ) ) ) {
* Fires immediately after a comment is deleted from the database.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The deleted comment.
do_action( 'deleted_comment', $comment->comment_ID, $comment );