wp/wp-includes/comment.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 <?php
       
     2 /**
       
     3  * Manages WordPress comments
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage Comment
       
     7  */
       
     8 
       
     9 /**
       
    10  * Checks whether a comment passes internal checks to be allowed to add.
       
    11  *
       
    12  * If comment moderation is set in the administration, then all comments,
       
    13  * regardless of their type and whitelist will be set to false. If the number of
       
    14  * links exceeds the amount in the administration, then the check fails. If any
       
    15  * of the parameter contents match the blacklist of words, then the check fails.
       
    16  *
       
    17  * If the number of links exceeds the amount in the administration, then the
       
    18  * check fails. If any of the parameter contents match the blacklist of words,
       
    19  * then the check fails.
       
    20  *
       
    21  * If the comment author was approved before, then the comment is
       
    22  * automatically whitelisted.
       
    23  *
       
    24  * If none of the checks fail, then the failback is to set the check to pass
       
    25  * (return true).
       
    26  *
       
    27  * @since 1.2.0
       
    28  * @uses $wpdb
       
    29  *
       
    30  * @param string $author Comment Author's name
       
    31  * @param string $email Comment Author's email
       
    32  * @param string $url Comment Author's URL
       
    33  * @param string $comment Comment contents
       
    34  * @param string $user_ip Comment Author's IP address
       
    35  * @param string $user_agent Comment Author's User Agent
       
    36  * @param string $comment_type Comment type, either user submitted comment,
       
    37  *		trackback, or pingback
       
    38  * @return bool Whether the checks passed (true) and the comments should be
       
    39  *		displayed or set to moderated
       
    40  */
       
    41 function check_comment($author, $email, $url, $comment, $user_ip, $user_agent, $comment_type) {
       
    42 	global $wpdb;
       
    43 
       
    44 	if ( 1 == get_option('comment_moderation') )
       
    45 		return false; // If moderation is set to manual
       
    46 
       
    47 	$comment = apply_filters( 'comment_text', $comment );
       
    48 
       
    49 	// Check # of external links
       
    50 	if ( $max_links = get_option( 'comment_max_links' ) ) {
       
    51 		$num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
       
    52 		$num_links = apply_filters( 'comment_max_links_url', $num_links, $url ); // provide for counting of $url as a link
       
    53 		if ( $num_links >= $max_links )
       
    54 			return false;
       
    55 	}
       
    56 
       
    57 	$mod_keys = trim(get_option('moderation_keys'));
       
    58 	if ( !empty($mod_keys) ) {
       
    59 		$words = explode("\n", $mod_keys );
       
    60 
       
    61 		foreach ( (array) $words as $word) {
       
    62 			$word = trim($word);
       
    63 
       
    64 			// Skip empty lines
       
    65 			if ( empty($word) )
       
    66 				continue;
       
    67 
       
    68 			// Do some escaping magic so that '#' chars in the
       
    69 			// spam words don't break things:
       
    70 			$word = preg_quote($word, '#');
       
    71 
       
    72 			$pattern = "#$word#i";
       
    73 			if ( preg_match($pattern, $author) ) return false;
       
    74 			if ( preg_match($pattern, $email) ) return false;
       
    75 			if ( preg_match($pattern, $url) ) return false;
       
    76 			if ( preg_match($pattern, $comment) ) return false;
       
    77 			if ( preg_match($pattern, $user_ip) ) return false;
       
    78 			if ( preg_match($pattern, $user_agent) ) return false;
       
    79 		}
       
    80 	}
       
    81 
       
    82 	// Comment whitelisting:
       
    83 	if ( 1 == get_option('comment_whitelist')) {
       
    84 		if ( 'trackback' != $comment_type && 'pingback' != $comment_type && $author != '' && $email != '' ) {
       
    85 			// expected_slashed ($author, $email)
       
    86 			$ok_to_comment = $wpdb->get_var("SELECT comment_approved FROM $wpdb->comments WHERE comment_author = '$author' AND comment_author_email = '$email' and comment_approved = '1' LIMIT 1");
       
    87 			if ( ( 1 == $ok_to_comment ) &&
       
    88 				( empty($mod_keys) || false === strpos( $email, $mod_keys) ) )
       
    89 					return true;
       
    90 			else
       
    91 				return false;
       
    92 		} else {
       
    93 			return false;
       
    94 		}
       
    95 	}
       
    96 	return true;
       
    97 }
       
    98 
       
    99 /**
       
   100  * Retrieve the approved comments for post $post_id.
       
   101  *
       
   102  * @since 2.0.0
       
   103  * @uses $wpdb
       
   104  *
       
   105  * @param int $post_id The ID of the post
       
   106  * @return array $comments The approved comments
       
   107  */
       
   108 function get_approved_comments($post_id) {
       
   109 	global $wpdb;
       
   110 	return $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1' ORDER BY comment_date", $post_id));
       
   111 }
       
   112 
       
   113 /**
       
   114  * Retrieves comment data given a comment ID or comment object.
       
   115  *
       
   116  * If an object is passed then the comment data will be cached and then returned
       
   117  * after being passed through a filter. If the comment is empty, then the global
       
   118  * comment variable will be used, if it is set.
       
   119  *
       
   120  * @since 2.0.0
       
   121  * @uses $wpdb
       
   122  *
       
   123  * @param object|string|int $comment Comment to retrieve.
       
   124  * @param string $output Optional. OBJECT or ARRAY_A or ARRAY_N constants.
       
   125  * @return object|array|null Depends on $output value.
       
   126  */
       
   127 function get_comment(&$comment, $output = OBJECT) {
       
   128 	global $wpdb;
       
   129 	$null = null;
       
   130 
       
   131 	if ( empty($comment) ) {
       
   132 		if ( isset($GLOBALS['comment']) )
       
   133 			$_comment = & $GLOBALS['comment'];
       
   134 		else
       
   135 			$_comment = null;
       
   136 	} elseif ( is_object($comment) ) {
       
   137 		wp_cache_add($comment->comment_ID, $comment, 'comment');
       
   138 		$_comment = $comment;
       
   139 	} else {
       
   140 		if ( isset($GLOBALS['comment']) && ($GLOBALS['comment']->comment_ID == $comment) ) {
       
   141 			$_comment = & $GLOBALS['comment'];
       
   142 		} elseif ( ! $_comment = wp_cache_get($comment, 'comment') ) {
       
   143 			$_comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_ID = %d LIMIT 1", $comment));
       
   144 			if ( ! $_comment )
       
   145 				return $null;
       
   146 			wp_cache_add($_comment->comment_ID, $_comment, 'comment');
       
   147 		}
       
   148 	}
       
   149 
       
   150 	$_comment = apply_filters('get_comment', $_comment);
       
   151 
       
   152 	if ( $output == OBJECT ) {
       
   153 		return $_comment;
       
   154 	} elseif ( $output == ARRAY_A ) {
       
   155 		$__comment = get_object_vars($_comment);
       
   156 		return $__comment;
       
   157 	} elseif ( $output == ARRAY_N ) {
       
   158 		$__comment = array_values(get_object_vars($_comment));
       
   159 		return $__comment;
       
   160 	} else {
       
   161 		return $_comment;
       
   162 	}
       
   163 }
       
   164 
       
   165 /**
       
   166  * Retrieve a list of comments.
       
   167  *
       
   168  * The comment list can be for the blog as a whole or for an individual post.
       
   169  *
       
   170  * The list of comment arguments are 'status', 'orderby', 'comment_date_gmt',
       
   171  * 'order', 'number', 'offset', and 'post_id'.
       
   172  *
       
   173  * @since 2.7.0
       
   174  * @uses $wpdb
       
   175  *
       
   176  * @param mixed $args Optional. Array or string of options to override defaults.
       
   177  * @return array List of comments.
       
   178  */
       
   179 function get_comments( $args = '' ) {
       
   180 	$query = new WP_Comment_Query;
       
   181 	return $query->query( $args );
       
   182 }
       
   183 
       
   184 /**
       
   185  * WordPress Comment Query class.
       
   186  *
       
   187  * @since 3.1.0
       
   188  */
       
   189 class WP_Comment_Query {
       
   190 	/**
       
   191 	 * Metadata query container
       
   192 	 *
       
   193 	 * @since 3.5.0
       
   194 	 * @access public
       
   195 	 * @var object WP_Meta_Query
       
   196 	 */
       
   197 	var $meta_query = false;
       
   198 
       
   199 	/**
       
   200 	 * Date query container
       
   201 	 *
       
   202 	 * @since 3.7.0
       
   203 	 * @access public
       
   204 	 * @var object WP_Date_Query
       
   205 	 */
       
   206 	var $date_query = false;
       
   207 
       
   208 	/**
       
   209 	 * Execute the query
       
   210 	 *
       
   211 	 * @since 3.1.0
       
   212 	 *
       
   213 	 * @param string|array $query_vars
       
   214 	 * @return int|array
       
   215 	 */
       
   216 	function query( $query_vars ) {
       
   217 		global $wpdb;
       
   218 
       
   219 		$defaults = array(
       
   220 			'author_email' => '',
       
   221 			'ID' => '',
       
   222 			'karma' => '',
       
   223 			'number' => '',
       
   224 			'offset' => '',
       
   225 			'orderby' => '',
       
   226 			'order' => 'DESC',
       
   227 			'parent' => '',
       
   228 			'post_ID' => '',
       
   229 			'post_id' => 0,
       
   230 			'post_author' => '',
       
   231 			'post_name' => '',
       
   232 			'post_parent' => '',
       
   233 			'post_status' => '',
       
   234 			'post_type' => '',
       
   235 			'status' => '',
       
   236 			'type' => '',
       
   237 			'user_id' => '',
       
   238 			'search' => '',
       
   239 			'count' => false,
       
   240 			'meta_key' => '',
       
   241 			'meta_value' => '',
       
   242 			'meta_query' => '',
       
   243 			'date_query' => null, // See WP_Date_Query
       
   244 		);
       
   245 
       
   246 		$groupby = '';
       
   247 
       
   248 		$this->query_vars = wp_parse_args( $query_vars, $defaults );
       
   249 
       
   250 		// Parse meta query
       
   251 		$this->meta_query = new WP_Meta_Query();
       
   252 		$this->meta_query->parse_query_vars( $this->query_vars );
       
   253 
       
   254 		do_action_ref_array( 'pre_get_comments', array( &$this ) );
       
   255 		extract( $this->query_vars, EXTR_SKIP );
       
   256 
       
   257 		// $args can be whatever, only use the args defined in defaults to compute the key
       
   258 		$key = md5( serialize( compact(array_keys($defaults)) )  );
       
   259 		$last_changed = wp_cache_get( 'last_changed', 'comment' );
       
   260 		if ( ! $last_changed ) {
       
   261 			$last_changed = microtime();
       
   262 			wp_cache_set( 'last_changed', $last_changed, 'comment' );
       
   263 		}
       
   264 		$cache_key = "get_comments:$key:$last_changed";
       
   265 
       
   266 		if ( $cache = wp_cache_get( $cache_key, 'comment' ) )
       
   267 			return $cache;
       
   268 
       
   269 		$post_id = absint($post_id);
       
   270 
       
   271 		if ( 'hold' == $status )
       
   272 			$approved = "comment_approved = '0'";
       
   273 		elseif ( 'approve' == $status )
       
   274 			$approved = "comment_approved = '1'";
       
   275 		elseif ( ! empty( $status ) && 'all' != $status )
       
   276 			$approved = $wpdb->prepare( "comment_approved = %s", $status );
       
   277 		else
       
   278 			$approved = "( comment_approved = '0' OR comment_approved = '1' )";
       
   279 
       
   280 		$order = ( 'ASC' == strtoupper($order) ) ? 'ASC' : 'DESC';
       
   281 
       
   282 		if ( ! empty( $orderby ) ) {
       
   283 			$ordersby = is_array($orderby) ? $orderby : preg_split('/[,\s]/', $orderby);
       
   284 			$allowed_keys = array(
       
   285 				'comment_agent',
       
   286 				'comment_approved',
       
   287 				'comment_author',
       
   288 				'comment_author_email',
       
   289 				'comment_author_IP',
       
   290 				'comment_author_url',
       
   291 				'comment_content',
       
   292 				'comment_date',
       
   293 				'comment_date_gmt',
       
   294 				'comment_ID',
       
   295 				'comment_karma',
       
   296 				'comment_parent',
       
   297 				'comment_post_ID',
       
   298 				'comment_type',
       
   299 				'user_id',
       
   300 			);
       
   301 			if ( ! empty( $this->query_vars['meta_key'] ) ) {
       
   302 				$allowed_keys[] = $this->query_vars['meta_key'];
       
   303 				$allowed_keys[] = 'meta_value';
       
   304 				$allowed_keys[] = 'meta_value_num';
       
   305 			}
       
   306 			$ordersby = array_intersect( $ordersby, $allowed_keys );
       
   307 			foreach ( $ordersby as $key => $value ) {
       
   308 				if ( $value == $this->query_vars['meta_key'] || $value == 'meta_value' ) {
       
   309 					$ordersby[ $key ] = "$wpdb->commentmeta.meta_value";
       
   310 				} elseif ( $value == 'meta_value_num' ) {
       
   311 					$ordersby[ $key ] = "$wpdb->commentmeta.meta_value+0";
       
   312 				}
       
   313 			}
       
   314 			$orderby = empty( $ordersby ) ? 'comment_date_gmt' : implode(', ', $ordersby);
       
   315 		} else {
       
   316 			$orderby = 'comment_date_gmt';
       
   317 		}
       
   318 
       
   319 		$number = absint($number);
       
   320 		$offset = absint($offset);
       
   321 
       
   322 		if ( !empty($number) ) {
       
   323 			if ( $offset )
       
   324 				$limits = 'LIMIT ' . $offset . ',' . $number;
       
   325 			else
       
   326 				$limits = 'LIMIT ' . $number;
       
   327 		} else {
       
   328 			$limits = '';
       
   329 		}
       
   330 
       
   331 		if ( $count )
       
   332 			$fields = 'COUNT(*)';
       
   333 		else
       
   334 			$fields = '*';
       
   335 
       
   336 		$join = '';
       
   337 		$where = $approved;
       
   338 
       
   339 		if ( ! empty($post_id) )
       
   340 			$where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
       
   341 		if ( '' !== $author_email )
       
   342 			$where .= $wpdb->prepare( ' AND comment_author_email = %s', $author_email );
       
   343 		if ( '' !== $karma )
       
   344 			$where .= $wpdb->prepare( ' AND comment_karma = %d', $karma );
       
   345 		if ( 'comment' == $type ) {
       
   346 			$where .= " AND comment_type = ''";
       
   347 		} elseif( 'pings' == $type ) {
       
   348 			$where .= ' AND comment_type IN ("pingback", "trackback")';
       
   349 		} elseif ( ! empty( $type ) ) {
       
   350 			$where .= $wpdb->prepare( ' AND comment_type = %s', $type );
       
   351 		}
       
   352 		if ( '' !== $parent )
       
   353 			$where .= $wpdb->prepare( ' AND comment_parent = %d', $parent );
       
   354 		if ( '' !== $user_id )
       
   355 			$where .= $wpdb->prepare( ' AND user_id = %d', $user_id );
       
   356 		if ( '' !== $search )
       
   357 			$where .= $this->get_search_sql( $search, array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_content' ) );
       
   358 
       
   359 		$post_fields = array_filter( compact( array( 'post_author', 'post_name', 'post_parent', 'post_status', 'post_type', ) ) );
       
   360 		if ( ! empty( $post_fields ) ) {
       
   361 			$join = "JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID";
       
   362 			foreach( $post_fields as $field_name => $field_value )
       
   363 				$where .= $wpdb->prepare( " AND {$wpdb->posts}.{$field_name} = %s", $field_value );
       
   364 		}
       
   365 
       
   366 		if ( ! empty( $this->meta_query->queries ) ) {
       
   367 			$clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this );
       
   368 			$join .= $clauses['join'];
       
   369 			$where .= $clauses['where'];
       
   370 			$groupby = "{$wpdb->comments}.comment_ID";
       
   371 		}
       
   372 
       
   373 		if ( ! empty( $date_query ) && is_array( $date_query ) ) {
       
   374 			$date_query_object = new WP_Date_Query( $date_query, 'comment_date' );
       
   375 			$where .= $date_query_object->get_sql();
       
   376 		}
       
   377 
       
   378 		$pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits', 'groupby' );
       
   379 		$clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );
       
   380 		foreach ( $pieces as $piece )
       
   381 			$$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
       
   382 
       
   383 		if ( $groupby )
       
   384 			$groupby = 'GROUP BY ' . $groupby;
       
   385 
       
   386 		$query = "SELECT $fields FROM $wpdb->comments $join WHERE $where $groupby ORDER BY $orderby $order $limits";
       
   387 
       
   388 		if ( $count )
       
   389 			return $wpdb->get_var( $query );
       
   390 
       
   391 		$comments = $wpdb->get_results( $query );
       
   392 		$comments = apply_filters_ref_array( 'the_comments', array( $comments, &$this ) );
       
   393 
       
   394 		wp_cache_add( $cache_key, $comments, 'comment' );
       
   395 
       
   396 		return $comments;
       
   397 	}
       
   398 
       
   399 	/*
       
   400 	 * Used internally to generate an SQL string for searching across multiple columns
       
   401 	 *
       
   402 	 * @access protected
       
   403 	 * @since 3.1.0
       
   404 	 *
       
   405 	 * @param string $string
       
   406 	 * @param array $cols
       
   407 	 * @return string
       
   408 	 */
       
   409 	function get_search_sql( $string, $cols ) {
       
   410 		$string = esc_sql( like_escape( $string ) );
       
   411 
       
   412 		$searches = array();
       
   413 		foreach ( $cols as $col )
       
   414 			$searches[] = "$col LIKE '%$string%'";
       
   415 
       
   416 		return ' AND (' . implode(' OR ', $searches) . ')';
       
   417 	}
       
   418 }
       
   419 
       
   420 /**
       
   421  * Retrieve all of the WordPress supported comment statuses.
       
   422  *
       
   423  * Comments have a limited set of valid status values, this provides the comment
       
   424  * status values and descriptions.
       
   425  *
       
   426  * @package WordPress
       
   427  * @subpackage Post
       
   428  * @since 2.7.0
       
   429  *
       
   430  * @return array List of comment statuses.
       
   431  */
       
   432 function get_comment_statuses() {
       
   433 	$status = array(
       
   434 		'hold'		=> __('Unapproved'),
       
   435 		/* translators: comment status  */
       
   436 		'approve'	=> _x('Approved', 'adjective'),
       
   437 		/* translators: comment status */
       
   438 		'spam'		=> _x('Spam', 'adjective'),
       
   439 	);
       
   440 
       
   441 	return $status;
       
   442 }
       
   443 
       
   444 /**
       
   445  * The date the last comment was modified.
       
   446  *
       
   447  * @since 1.5.0
       
   448  * @uses $wpdb
       
   449  *
       
   450  * @param string $timezone Which timezone to use in reference to 'gmt', 'blog',
       
   451  *		or 'server' locations.
       
   452  * @return string Last comment modified date.
       
   453  */
       
   454 function get_lastcommentmodified($timezone = 'server') {
       
   455 	global $wpdb;
       
   456 	static $cache_lastcommentmodified = array();
       
   457 
       
   458 	if ( isset($cache_lastcommentmodified[$timezone]) )
       
   459 		return $cache_lastcommentmodified[$timezone];
       
   460 
       
   461 	$add_seconds_server = date('Z');
       
   462 
       
   463 	switch ( strtolower($timezone)) {
       
   464 		case 'gmt':
       
   465 			$lastcommentmodified = $wpdb->get_var("SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
       
   466 			break;
       
   467 		case 'blog':
       
   468 			$lastcommentmodified = $wpdb->get_var("SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
       
   469 			break;
       
   470 		case 'server':
       
   471 			$lastcommentmodified = $wpdb->get_var($wpdb->prepare("SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server));
       
   472 			break;
       
   473 	}
       
   474 
       
   475 	$cache_lastcommentmodified[$timezone] = $lastcommentmodified;
       
   476 
       
   477 	return $lastcommentmodified;
       
   478 }
       
   479 
       
   480 /**
       
   481  * The amount of comments in a post or total comments.
       
   482  *
       
   483  * A lot like {@link wp_count_comments()}, in that they both return comment
       
   484  * stats (albeit with different types). The {@link wp_count_comments()} actual
       
   485  * caches, but this function does not.
       
   486  *
       
   487  * @since 2.0.0
       
   488  * @uses $wpdb
       
   489  *
       
   490  * @param int $post_id Optional. Comment amount in post if > 0, else total comments blog wide.
       
   491  * @return array The amount of spam, approved, awaiting moderation, and total comments.
       
   492  */
       
   493 function get_comment_count( $post_id = 0 ) {
       
   494 	global $wpdb;
       
   495 
       
   496 	$post_id = (int) $post_id;
       
   497 
       
   498 	$where = '';
       
   499 	if ( $post_id > 0 ) {
       
   500 		$where = $wpdb->prepare("WHERE comment_post_ID = %d", $post_id);
       
   501 	}
       
   502 
       
   503 	$totals = (array) $wpdb->get_results("
       
   504 		SELECT comment_approved, COUNT( * ) AS total
       
   505 		FROM {$wpdb->comments}
       
   506 		{$where}
       
   507 		GROUP BY comment_approved
       
   508 	", ARRAY_A);
       
   509 
       
   510 	$comment_count = array(
       
   511 		"approved"              => 0,
       
   512 		"awaiting_moderation"   => 0,
       
   513 		"spam"                  => 0,
       
   514 		"total_comments"        => 0
       
   515 	);
       
   516 
       
   517 	foreach ( $totals as $row ) {
       
   518 		switch ( $row['comment_approved'] ) {
       
   519 			case 'spam':
       
   520 				$comment_count['spam'] = $row['total'];
       
   521 				$comment_count["total_comments"] += $row['total'];
       
   522 				break;
       
   523 			case 1:
       
   524 				$comment_count['approved'] = $row['total'];
       
   525 				$comment_count['total_comments'] += $row['total'];
       
   526 				break;
       
   527 			case 0:
       
   528 				$comment_count['awaiting_moderation'] = $row['total'];
       
   529 				$comment_count['total_comments'] += $row['total'];
       
   530 				break;
       
   531 			default:
       
   532 				break;
       
   533 		}
       
   534 	}
       
   535 
       
   536 	return $comment_count;
       
   537 }
       
   538 
       
   539 //
       
   540 // Comment meta functions
       
   541 //
       
   542 
       
   543 /**
       
   544  * Add meta data field to a comment.
       
   545  *
       
   546  * @since 2.9.0
       
   547  * @uses add_metadata
       
   548  * @link http://codex.wordpress.org/Function_Reference/add_comment_meta
       
   549  *
       
   550  * @param int $comment_id Comment ID.
       
   551  * @param string $meta_key Metadata name.
       
   552  * @param mixed $meta_value Metadata value.
       
   553  * @param bool $unique Optional, default is false. Whether the same key should not be added.
       
   554  * @return int|bool Meta ID on success, false on failure.
       
   555  */
       
   556 function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
       
   557 	return add_metadata('comment', $comment_id, $meta_key, $meta_value, $unique);
       
   558 }
       
   559 
       
   560 /**
       
   561  * Remove metadata matching criteria from a comment.
       
   562  *
       
   563  * You can match based on the key, or key and value. Removing based on key and
       
   564  * value, will keep from removing duplicate metadata with the same key. It also
       
   565  * allows removing all metadata matching key, if needed.
       
   566  *
       
   567  * @since 2.9.0
       
   568  * @uses delete_metadata
       
   569  * @link http://codex.wordpress.org/Function_Reference/delete_comment_meta
       
   570  *
       
   571  * @param int $comment_id comment ID
       
   572  * @param string $meta_key Metadata name.
       
   573  * @param mixed $meta_value Optional. Metadata value.
       
   574  * @return bool True on success, false on failure.
       
   575  */
       
   576 function delete_comment_meta($comment_id, $meta_key, $meta_value = '') {
       
   577 	return delete_metadata('comment', $comment_id, $meta_key, $meta_value);
       
   578 }
       
   579 
       
   580 /**
       
   581  * Retrieve comment meta field for a comment.
       
   582  *
       
   583  * @since 2.9.0
       
   584  * @uses get_metadata
       
   585  * @link http://codex.wordpress.org/Function_Reference/get_comment_meta
       
   586  *
       
   587  * @param int $comment_id Comment ID.
       
   588  * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
       
   589  * @param bool $single Whether to return a single value.
       
   590  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
       
   591  *  is true.
       
   592  */
       
   593 function get_comment_meta($comment_id, $key = '', $single = false) {
       
   594 	return get_metadata('comment', $comment_id, $key, $single);
       
   595 }
       
   596 
       
   597 /**
       
   598  * Update comment meta field based on comment ID.
       
   599  *
       
   600  * Use the $prev_value parameter to differentiate between meta fields with the
       
   601  * same key and comment ID.
       
   602  *
       
   603  * If the meta field for the comment does not exist, it will be added.
       
   604  *
       
   605  * @since 2.9.0
       
   606  * @uses update_metadata
       
   607  * @link http://codex.wordpress.org/Function_Reference/update_comment_meta
       
   608  *
       
   609  * @param int $comment_id Comment ID.
       
   610  * @param string $meta_key Metadata key.
       
   611  * @param mixed $meta_value Metadata value.
       
   612  * @param mixed $prev_value Optional. Previous value to check before removing.
       
   613  * @return bool True on success, false on failure.
       
   614  */
       
   615 function update_comment_meta($comment_id, $meta_key, $meta_value, $prev_value = '') {
       
   616 	return update_metadata('comment', $comment_id, $meta_key, $meta_value, $prev_value);
       
   617 }
       
   618 
       
   619 /**
       
   620  * Sets the cookies used to store an unauthenticated commentator's identity. Typically used
       
   621  * to recall previous comments by this commentator that are still held in moderation.
       
   622  *
       
   623  * @param object $comment Comment object.
       
   624  * @param object $user Comment author's object.
       
   625  *
       
   626  * @since 3.4.0
       
   627  */
       
   628 function wp_set_comment_cookies($comment, $user) {
       
   629 	if ( $user->exists() )
       
   630 		return;
       
   631 
       
   632 	$comment_cookie_lifetime = apply_filters('comment_cookie_lifetime', 30000000);
       
   633 	setcookie('comment_author_' . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
       
   634 	setcookie('comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
       
   635 	setcookie('comment_author_url_' . COOKIEHASH, esc_url($comment->comment_author_url), time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
       
   636 }
       
   637 
       
   638 /**
       
   639  * Sanitizes the cookies sent to the user already.
       
   640  *
       
   641  * Will only do anything if the cookies have already been created for the user.
       
   642  * Mostly used after cookies had been sent to use elsewhere.
       
   643  *
       
   644  * @since 2.0.4
       
   645  */
       
   646 function sanitize_comment_cookies() {
       
   647 	if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) ) {
       
   648 		$comment_author = apply_filters('pre_comment_author_name', $_COOKIE['comment_author_'.COOKIEHASH]);
       
   649 		$comment_author = wp_unslash($comment_author);
       
   650 		$comment_author = esc_attr($comment_author);
       
   651 		$_COOKIE['comment_author_'.COOKIEHASH] = $comment_author;
       
   652 	}
       
   653 
       
   654 	if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) ) {
       
   655 		$comment_author_email = apply_filters('pre_comment_author_email', $_COOKIE['comment_author_email_'.COOKIEHASH]);
       
   656 		$comment_author_email = wp_unslash($comment_author_email);
       
   657 		$comment_author_email = esc_attr($comment_author_email);
       
   658 		$_COOKIE['comment_author_email_'.COOKIEHASH] = $comment_author_email;
       
   659 	}
       
   660 
       
   661 	if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) ) {
       
   662 		$comment_author_url = apply_filters('pre_comment_author_url', $_COOKIE['comment_author_url_'.COOKIEHASH]);
       
   663 		$comment_author_url = wp_unslash($comment_author_url);
       
   664 		$_COOKIE['comment_author_url_'.COOKIEHASH] = $comment_author_url;
       
   665 	}
       
   666 }
       
   667 
       
   668 /**
       
   669  * Validates whether this comment is allowed to be made.
       
   670  *
       
   671  * @since 2.0.0
       
   672  * @uses $wpdb
       
   673  * @uses apply_filters() Calls 'pre_comment_approved' hook on the type of comment
       
   674  * @uses apply_filters() Calls 'comment_duplicate_trigger' hook on commentdata.
       
   675  * @uses do_action() Calls 'check_comment_flood' hook on $comment_author_IP, $comment_author_email, and $comment_date_gmt
       
   676  *
       
   677  * @param array $commentdata Contains information on the comment
       
   678  * @return mixed Signifies the approval status (0|1|'spam')
       
   679  */
       
   680 function wp_allow_comment($commentdata) {
       
   681 	global $wpdb;
       
   682 	extract($commentdata, EXTR_SKIP);
       
   683 
       
   684 	// Simple duplicate check
       
   685 	// expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
       
   686 	$dupe = $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = %s AND comment_approved != 'trash' AND ( comment_author = %s ", wp_unslash( $comment_post_ID ), wp_unslash( $comment_parent ), wp_unslash( $comment_author ) );
       
   687 	if ( $comment_author_email )
       
   688 		$dupe .= $wpdb->prepare( "OR comment_author_email = %s ", wp_unslash( $comment_author_email ) );
       
   689 	$dupe .= $wpdb->prepare( ") AND comment_content = %s LIMIT 1", wp_unslash( $comment_content ) );
       
   690 	if ( $wpdb->get_var($dupe) ) {
       
   691 		do_action( 'comment_duplicate_trigger', $commentdata );
       
   692 		if ( defined('DOING_AJAX') )
       
   693 			die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
       
   694 
       
   695 		wp_die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
       
   696 	}
       
   697 
       
   698 	do_action( 'check_comment_flood', $comment_author_IP, $comment_author_email, $comment_date_gmt );
       
   699 
       
   700 	if ( ! empty( $user_id ) ) {
       
   701 		$user = get_userdata( $user_id );
       
   702 		$post_author = $wpdb->get_var($wpdb->prepare("SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1", $comment_post_ID));
       
   703 	}
       
   704 
       
   705 	if ( isset( $user ) && ( $user_id == $post_author || $user->has_cap( 'moderate_comments' ) ) ) {
       
   706 		// The author and the admins get respect.
       
   707 		$approved = 1;
       
   708 	 } else {
       
   709 		// Everyone else's comments will be checked.
       
   710 		if ( check_comment($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent, $comment_type) )
       
   711 			$approved = 1;
       
   712 		else
       
   713 			$approved = 0;
       
   714 		if ( wp_blacklist_check($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent) )
       
   715 			$approved = 'spam';
       
   716 	}
       
   717 
       
   718 	$approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );
       
   719 	return $approved;
       
   720 }
       
   721 
       
   722 /**
       
   723  * Check whether comment flooding is occurring.
       
   724  *
       
   725  * Won't run, if current user can manage options, so to not block
       
   726  * administrators.
       
   727  *
       
   728  * @since 2.3.0
       
   729  * @uses $wpdb
       
   730  * @uses apply_filters() Calls 'comment_flood_filter' filter with first
       
   731  *		parameter false, last comment timestamp, new comment timestamp.
       
   732  * @uses do_action() Calls 'comment_flood_trigger' action with parameters with
       
   733  *		last comment timestamp and new comment timestamp.
       
   734  *
       
   735  * @param string $ip Comment IP.
       
   736  * @param string $email Comment author email address.
       
   737  * @param string $date MySQL time string.
       
   738  */
       
   739 function check_comment_flood_db( $ip, $email, $date ) {
       
   740 	global $wpdb;
       
   741 	if ( current_user_can( 'manage_options' ) )
       
   742 		return; // don't throttle admins
       
   743 	$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
       
   744 	if ( $lasttime = $wpdb->get_var( $wpdb->prepare( "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( `comment_author_IP` = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1", $hour_ago, $ip, $email ) ) ) {
       
   745 		$time_lastcomment = mysql2date('U', $lasttime, false);
       
   746 		$time_newcomment  = mysql2date('U', $date, false);
       
   747 		$flood_die = apply_filters('comment_flood_filter', false, $time_lastcomment, $time_newcomment);
       
   748 		if ( $flood_die ) {
       
   749 			do_action('comment_flood_trigger', $time_lastcomment, $time_newcomment);
       
   750 
       
   751 			if ( defined('DOING_AJAX') )
       
   752 				die( __('You are posting comments too quickly. Slow down.') );
       
   753 
       
   754 			wp_die( __('You are posting comments too quickly. Slow down.'), '', array('response' => 403) );
       
   755 		}
       
   756 	}
       
   757 }
       
   758 
       
   759 /**
       
   760  * Separates an array of comments into an array keyed by comment_type.
       
   761  *
       
   762  * @since 2.7.0
       
   763  *
       
   764  * @param array $comments Array of comments
       
   765  * @return array Array of comments keyed by comment_type.
       
   766  */
       
   767 function separate_comments(&$comments) {
       
   768 	$comments_by_type = array('comment' => array(), 'trackback' => array(), 'pingback' => array(), 'pings' => array());
       
   769 	$count = count($comments);
       
   770 	for ( $i = 0; $i < $count; $i++ ) {
       
   771 		$type = $comments[$i]->comment_type;
       
   772 		if ( empty($type) )
       
   773 			$type = 'comment';
       
   774 		$comments_by_type[$type][] = &$comments[$i];
       
   775 		if ( 'trackback' == $type || 'pingback' == $type )
       
   776 			$comments_by_type['pings'][] = &$comments[$i];
       
   777 	}
       
   778 
       
   779 	return $comments_by_type;
       
   780 }
       
   781 
       
   782 /**
       
   783  * Calculate the total number of comment pages.
       
   784  *
       
   785  * @since 2.7.0
       
   786  * @uses get_query_var() Used to fill in the default for $per_page parameter.
       
   787  * @uses get_option() Used to fill in defaults for parameters.
       
   788  * @uses Walker_Comment
       
   789  *
       
   790  * @param array $comments Optional array of comment objects. Defaults to $wp_query->comments
       
   791  * @param int $per_page Optional comments per page.
       
   792  * @param boolean $threaded Optional control over flat or threaded comments.
       
   793  * @return int Number of comment pages.
       
   794  */
       
   795 function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
       
   796 	global $wp_query;
       
   797 
       
   798 	if ( null === $comments && null === $per_page && null === $threaded && !empty($wp_query->max_num_comment_pages) )
       
   799 		return $wp_query->max_num_comment_pages;
       
   800 
       
   801 	if ( !$comments || !is_array($comments) )
       
   802 		$comments = $wp_query->comments;
       
   803 
       
   804 	if ( empty($comments) )
       
   805 		return 0;
       
   806 
       
   807 	if ( ! get_option( 'page_comments' ) )
       
   808 		return 1;
       
   809 
       
   810 	if ( !isset($per_page) )
       
   811 		$per_page = (int) get_query_var('comments_per_page');
       
   812 	if ( 0 === $per_page )
       
   813 		$per_page = (int) get_option('comments_per_page');
       
   814 	if ( 0 === $per_page )
       
   815 		return 1;
       
   816 
       
   817 	if ( !isset($threaded) )
       
   818 		$threaded = get_option('thread_comments');
       
   819 
       
   820 	if ( $threaded ) {
       
   821 		$walker = new Walker_Comment;
       
   822 		$count = ceil( $walker->get_number_of_root_elements( $comments ) / $per_page );
       
   823 	} else {
       
   824 		$count = ceil( count( $comments ) / $per_page );
       
   825 	}
       
   826 
       
   827 	return $count;
       
   828 }
       
   829 
       
   830 /**
       
   831  * Calculate what page number a comment will appear on for comment paging.
       
   832  *
       
   833  * @since 2.7.0
       
   834  * @uses get_comment() Gets the full comment of the $comment_ID parameter.
       
   835  * @uses get_option() Get various settings to control function and defaults.
       
   836  * @uses get_page_of_comment() Used to loop up to top level comment.
       
   837  *
       
   838  * @param int $comment_ID Comment ID.
       
   839  * @param array $args Optional args.
       
   840  * @return int|null Comment page number or null on error.
       
   841  */
       
   842 function get_page_of_comment( $comment_ID, $args = array() ) {
       
   843 	global $wpdb;
       
   844 
       
   845 	if ( !$comment = get_comment( $comment_ID ) )
       
   846 		return;
       
   847 
       
   848 	$defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
       
   849 	$args = wp_parse_args( $args, $defaults );
       
   850 
       
   851 	if ( '' === $args['per_page'] && get_option('page_comments') )
       
   852 		$args['per_page'] = get_query_var('comments_per_page');
       
   853 	if ( empty($args['per_page']) ) {
       
   854 		$args['per_page'] = 0;
       
   855 		$args['page'] = 0;
       
   856 	}
       
   857 	if ( $args['per_page'] < 1 )
       
   858 		return 1;
       
   859 
       
   860 	if ( '' === $args['max_depth'] ) {
       
   861 		if ( get_option('thread_comments') )
       
   862 			$args['max_depth'] = get_option('thread_comments_depth');
       
   863 		else
       
   864 			$args['max_depth'] = -1;
       
   865 	}
       
   866 
       
   867 	// Find this comment's top level parent if threading is enabled
       
   868 	if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
       
   869 		return get_page_of_comment( $comment->comment_parent, $args );
       
   870 
       
   871 	$allowedtypes = array(
       
   872 		'comment' => '',
       
   873 		'pingback' => 'pingback',
       
   874 		'trackback' => 'trackback',
       
   875 	);
       
   876 
       
   877 	$comtypewhere = ( 'all' != $args['type'] && isset($allowedtypes[$args['type']]) ) ? " AND comment_type = '" . $allowedtypes[$args['type']] . "'" : '';
       
   878 
       
   879 	// Count comments older than this one
       
   880 	$oldercoms = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = 0 AND comment_approved = '1' AND comment_date_gmt < '%s'" . $comtypewhere, $comment->comment_post_ID, $comment->comment_date_gmt ) );
       
   881 
       
   882 	// No older comments? Then it's page #1.
       
   883 	if ( 0 == $oldercoms )
       
   884 		return 1;
       
   885 
       
   886 	// Divide comments older than this one by comments per page to get this comment's page number
       
   887 	return ceil( ( $oldercoms + 1 ) / $args['per_page'] );
       
   888 }
       
   889 
       
   890 /**
       
   891  * Does comment contain blacklisted characters or words.
       
   892  *
       
   893  * @since 1.5.0
       
   894  * @uses do_action() Calls 'wp_blacklist_check' hook for all parameters.
       
   895  *
       
   896  * @param string $author The author of the comment
       
   897  * @param string $email The email of the comment
       
   898  * @param string $url The url used in the comment
       
   899  * @param string $comment The comment content
       
   900  * @param string $user_ip The comment author IP address
       
   901  * @param string $user_agent The author's browser user agent
       
   902  * @return bool True if comment contains blacklisted content, false if comment does not
       
   903  */
       
   904 function wp_blacklist_check($author, $email, $url, $comment, $user_ip, $user_agent) {
       
   905 	do_action('wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent);
       
   906 
       
   907 	$mod_keys = trim( get_option('blacklist_keys') );
       
   908 	if ( '' == $mod_keys )
       
   909 		return false; // If moderation keys are empty
       
   910 	$words = explode("\n", $mod_keys );
       
   911 
       
   912 	foreach ( (array) $words as $word ) {
       
   913 		$word = trim($word);
       
   914 
       
   915 		// Skip empty lines
       
   916 		if ( empty($word) ) { continue; }
       
   917 
       
   918 		// Do some escaping magic so that '#' chars in the
       
   919 		// spam words don't break things:
       
   920 		$word = preg_quote($word, '#');
       
   921 
       
   922 		$pattern = "#$word#i";
       
   923 		if (
       
   924 			   preg_match($pattern, $author)
       
   925 			|| preg_match($pattern, $email)
       
   926 			|| preg_match($pattern, $url)
       
   927 			|| preg_match($pattern, $comment)
       
   928 			|| preg_match($pattern, $user_ip)
       
   929 			|| preg_match($pattern, $user_agent)
       
   930 		 )
       
   931 			return true;
       
   932 	}
       
   933 	return false;
       
   934 }
       
   935 
       
   936 /**
       
   937  * Retrieve total comments for blog or single post.
       
   938  *
       
   939  * The properties of the returned object contain the 'moderated', 'approved',
       
   940  * and spam comments for either the entire blog or single post. Those properties
       
   941  * contain the amount of comments that match the status. The 'total_comments'
       
   942  * property contains the integer of total comments.
       
   943  *
       
   944  * The comment stats are cached and then retrieved, if they already exist in the
       
   945  * cache.
       
   946  *
       
   947  * @since 2.5.0
       
   948  *
       
   949  * @param int $post_id Optional. Post ID.
       
   950  * @return object Comment stats.
       
   951  */
       
   952 function wp_count_comments( $post_id = 0 ) {
       
   953 	global $wpdb;
       
   954 
       
   955 	$post_id = (int) $post_id;
       
   956 
       
   957 	$stats = apply_filters('wp_count_comments', array(), $post_id);
       
   958 	if ( !empty($stats) )
       
   959 		return $stats;
       
   960 
       
   961 	$count = wp_cache_get("comments-{$post_id}", 'counts');
       
   962 
       
   963 	if ( false !== $count )
       
   964 		return $count;
       
   965 
       
   966 	$where = '';
       
   967 	if ( $post_id > 0 )
       
   968 		$where = $wpdb->prepare( "WHERE comment_post_ID = %d", $post_id );
       
   969 
       
   970 	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
       
   971 
       
   972 	$total = 0;
       
   973 	$approved = array('0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed');
       
   974 	foreach ( (array) $count as $row ) {
       
   975 		// Don't count post-trashed toward totals
       
   976 		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] )
       
   977 			$total += $row['num_comments'];
       
   978 		if ( isset( $approved[$row['comment_approved']] ) )
       
   979 			$stats[$approved[$row['comment_approved']]] = $row['num_comments'];
       
   980 	}
       
   981 
       
   982 	$stats['total_comments'] = $total;
       
   983 	foreach ( $approved as $key ) {
       
   984 		if ( empty($stats[$key]) )
       
   985 			$stats[$key] = 0;
       
   986 	}
       
   987 
       
   988 	$stats = (object) $stats;
       
   989 	wp_cache_set("comments-{$post_id}", $stats, 'counts');
       
   990 
       
   991 	return $stats;
       
   992 }
       
   993 
       
   994 /**
       
   995  * Trashes or deletes a comment.
       
   996  *
       
   997  * The comment is moved to trash instead of permanently deleted unless trash is
       
   998  * disabled, item is already in the trash, or $force_delete is true.
       
   999  *
       
  1000  * The post comment count will be updated if the comment was approved and has a
       
  1001  * post ID available.
       
  1002  *
       
  1003  * @since 2.0.0
       
  1004  * @uses $wpdb
       
  1005  * @uses do_action() Calls 'delete_comment' hook on comment ID
       
  1006  * @uses do_action() Calls 'deleted_comment' hook on comment ID after deletion, on success
       
  1007  * @uses do_action() Calls 'wp_set_comment_status' hook on comment ID with 'delete' set for the second parameter
       
  1008  * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
       
  1009  *
       
  1010  * @param int $comment_id Comment ID
       
  1011  * @param bool $force_delete Whether to bypass trash and force deletion. Default is false.
       
  1012  * @return bool True on success, false on failure.
       
  1013  */
       
  1014 function wp_delete_comment($comment_id, $force_delete = false) {
       
  1015 	global $wpdb;
       
  1016 	if (!$comment = get_comment($comment_id))
       
  1017 		return false;
       
  1018 
       
  1019 	if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status($comment_id), array( 'trash', 'spam' ) ) )
       
  1020 		return wp_trash_comment($comment_id);
       
  1021 
       
  1022 	do_action('delete_comment', $comment_id);
       
  1023 
       
  1024 	// Move children up a level.
       
  1025 	$children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment_id) );
       
  1026 	if ( !empty($children) ) {
       
  1027 		$wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment_id));
       
  1028 		clean_comment_cache($children);
       
  1029 	}
       
  1030 
       
  1031 	// Delete metadata
       
  1032 	$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment_id ) );
       
  1033 	foreach ( $meta_ids as $mid )
       
  1034 		delete_metadata_by_mid( 'comment', $mid );
       
  1035 
       
  1036 	if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment_id ) ) )
       
  1037 		return false;
       
  1038 	do_action('deleted_comment', $comment_id);
       
  1039 
       
  1040 	$post_id = $comment->comment_post_ID;
       
  1041 	if ( $post_id && $comment->comment_approved == 1 )
       
  1042 		wp_update_comment_count($post_id);
       
  1043 
       
  1044 	clean_comment_cache($comment_id);
       
  1045 
       
  1046 	do_action('wp_set_comment_status', $comment_id, 'delete');
       
  1047 	wp_transition_comment_status('delete', $comment->comment_approved, $comment);
       
  1048 	return true;
       
  1049 }
       
  1050 
       
  1051 /**
       
  1052  * Moves a comment to the Trash
       
  1053  *
       
  1054  * If trash is disabled, comment is permanently deleted.
       
  1055  *
       
  1056  * @since 2.9.0
       
  1057  * @uses do_action() on 'trash_comment' before trashing
       
  1058  * @uses do_action() on 'trashed_comment' after trashing
       
  1059  * @uses wp_delete_comment() if trash is disabled
       
  1060  *
       
  1061  * @param int $comment_id Comment ID.
       
  1062  * @return bool True on success, false on failure.
       
  1063  */
       
  1064 function wp_trash_comment($comment_id) {
       
  1065 	if ( !EMPTY_TRASH_DAYS )
       
  1066 		return wp_delete_comment($comment_id, true);
       
  1067 
       
  1068 	if ( !$comment = get_comment($comment_id) )
       
  1069 		return false;
       
  1070 
       
  1071 	do_action('trash_comment', $comment_id);
       
  1072 
       
  1073 	if ( wp_set_comment_status($comment_id, 'trash') ) {
       
  1074 		add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
       
  1075 		add_comment_meta($comment_id, '_wp_trash_meta_time', time() );
       
  1076 		do_action('trashed_comment', $comment_id);
       
  1077 		return true;
       
  1078 	}
       
  1079 
       
  1080 	return false;
       
  1081 }
       
  1082 
       
  1083 /**
       
  1084  * Removes a comment from the Trash
       
  1085  *
       
  1086  * @since 2.9.0
       
  1087  * @uses do_action() on 'untrash_comment' before untrashing
       
  1088  * @uses do_action() on 'untrashed_comment' after untrashing
       
  1089  *
       
  1090  * @param int $comment_id Comment ID.
       
  1091  * @return bool True on success, false on failure.
       
  1092  */
       
  1093 function wp_untrash_comment($comment_id) {
       
  1094 	if ( ! (int)$comment_id )
       
  1095 		return false;
       
  1096 
       
  1097 	do_action('untrash_comment', $comment_id);
       
  1098 
       
  1099 	$status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
       
  1100 	if ( empty($status) )
       
  1101 		$status = '0';
       
  1102 
       
  1103 	if ( wp_set_comment_status($comment_id, $status) ) {
       
  1104 		delete_comment_meta($comment_id, '_wp_trash_meta_time');
       
  1105 		delete_comment_meta($comment_id, '_wp_trash_meta_status');
       
  1106 		do_action('untrashed_comment', $comment_id);
       
  1107 		return true;
       
  1108 	}
       
  1109 
       
  1110 	return false;
       
  1111 }
       
  1112 
       
  1113 /**
       
  1114  * Marks a comment as Spam
       
  1115  *
       
  1116  * @since 2.9.0
       
  1117  * @uses do_action() on 'spam_comment' before spamming
       
  1118  * @uses do_action() on 'spammed_comment' after spamming
       
  1119  *
       
  1120  * @param int $comment_id Comment ID.
       
  1121  * @return bool True on success, false on failure.
       
  1122  */
       
  1123 function wp_spam_comment($comment_id) {
       
  1124 	if ( !$comment = get_comment($comment_id) )
       
  1125 		return false;
       
  1126 
       
  1127 	do_action('spam_comment', $comment_id);
       
  1128 
       
  1129 	if ( wp_set_comment_status($comment_id, 'spam') ) {
       
  1130 		add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
       
  1131 		do_action('spammed_comment', $comment_id);
       
  1132 		return true;
       
  1133 	}
       
  1134 
       
  1135 	return false;
       
  1136 }
       
  1137 
       
  1138 /**
       
  1139  * Removes a comment from the Spam
       
  1140  *
       
  1141  * @since 2.9.0
       
  1142  * @uses do_action() on 'unspam_comment' before unspamming
       
  1143  * @uses do_action() on 'unspammed_comment' after unspamming
       
  1144  *
       
  1145  * @param int $comment_id Comment ID.
       
  1146  * @return bool True on success, false on failure.
       
  1147  */
       
  1148 function wp_unspam_comment($comment_id) {
       
  1149 	if ( ! (int)$comment_id )
       
  1150 		return false;
       
  1151 
       
  1152 	do_action('unspam_comment', $comment_id);
       
  1153 
       
  1154 	$status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
       
  1155 	if ( empty($status) )
       
  1156 		$status = '0';
       
  1157 
       
  1158 	if ( wp_set_comment_status($comment_id, $status) ) {
       
  1159 		delete_comment_meta($comment_id, '_wp_trash_meta_status');
       
  1160 		do_action('unspammed_comment', $comment_id);
       
  1161 		return true;
       
  1162 	}
       
  1163 
       
  1164 	return false;
       
  1165 }
       
  1166 
       
  1167 /**
       
  1168  * The status of a comment by ID.
       
  1169  *
       
  1170  * @since 1.0.0
       
  1171  *
       
  1172  * @param int $comment_id Comment ID
       
  1173  * @return string|bool Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
       
  1174  */
       
  1175 function wp_get_comment_status($comment_id) {
       
  1176 	$comment = get_comment($comment_id);
       
  1177 	if ( !$comment )
       
  1178 		return false;
       
  1179 
       
  1180 	$approved = $comment->comment_approved;
       
  1181 
       
  1182 	if ( $approved == null )
       
  1183 		return false;
       
  1184 	elseif ( $approved == '1' )
       
  1185 		return 'approved';
       
  1186 	elseif ( $approved == '0' )
       
  1187 		return 'unapproved';
       
  1188 	elseif ( $approved == 'spam' )
       
  1189 		return 'spam';
       
  1190 	elseif ( $approved == 'trash' )
       
  1191 		return 'trash';
       
  1192 	else
       
  1193 		return false;
       
  1194 }
       
  1195 
       
  1196 /**
       
  1197  * Call hooks for when a comment status transition occurs.
       
  1198  *
       
  1199  * Calls hooks for comment status transitions. If the new comment status is not the same
       
  1200  * as the previous comment status, then two hooks will be ran, the first is
       
  1201  * 'transition_comment_status' with new status, old status, and comment data. The
       
  1202  * next action called is 'comment_OLDSTATUS_to_NEWSTATUS' the NEWSTATUS is the
       
  1203  * $new_status parameter and the OLDSTATUS is $old_status parameter; it has the
       
  1204  * comment data.
       
  1205  *
       
  1206  * The final action will run whether or not the comment statuses are the same. The
       
  1207  * action is named 'comment_NEWSTATUS_COMMENTTYPE', NEWSTATUS is from the $new_status
       
  1208  * parameter and COMMENTTYPE is comment_type comment data.
       
  1209  *
       
  1210  * @since 2.7.0
       
  1211  *
       
  1212  * @param string $new_status New comment status.
       
  1213  * @param string $old_status Previous comment status.
       
  1214  * @param object $comment Comment data.
       
  1215  */
       
  1216 function wp_transition_comment_status($new_status, $old_status, $comment) {
       
  1217 	// Translate raw statuses to human readable formats for the hooks
       
  1218 	// This is not a complete list of comment status, it's only the ones that need to be renamed
       
  1219 	$comment_statuses = array(
       
  1220 		0         => 'unapproved',
       
  1221 		'hold'    => 'unapproved', // wp_set_comment_status() uses "hold"
       
  1222 		1         => 'approved',
       
  1223 		'approve' => 'approved', // wp_set_comment_status() uses "approve"
       
  1224 	);
       
  1225 	if ( isset($comment_statuses[$new_status]) ) $new_status = $comment_statuses[$new_status];
       
  1226 	if ( isset($comment_statuses[$old_status]) ) $old_status = $comment_statuses[$old_status];
       
  1227 
       
  1228 	// Call the hooks
       
  1229 	if ( $new_status != $old_status ) {
       
  1230 		do_action('transition_comment_status', $new_status, $old_status, $comment);
       
  1231 		do_action("comment_{$old_status}_to_{$new_status}", $comment);
       
  1232 	}
       
  1233 	do_action("comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment);
       
  1234 }
       
  1235 
       
  1236 /**
       
  1237  * Get current commenter's name, email, and URL.
       
  1238  *
       
  1239  * Expects cookies content to already be sanitized. User of this function might
       
  1240  * wish to recheck the returned array for validity.
       
  1241  *
       
  1242  * @see sanitize_comment_cookies() Use to sanitize cookies
       
  1243  *
       
  1244  * @since 2.0.4
       
  1245  *
       
  1246  * @return array Comment author, email, url respectively.
       
  1247  */
       
  1248 function wp_get_current_commenter() {
       
  1249 	// Cookies should already be sanitized.
       
  1250 
       
  1251 	$comment_author = '';
       
  1252 	if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) )
       
  1253 		$comment_author = $_COOKIE['comment_author_'.COOKIEHASH];
       
  1254 
       
  1255 	$comment_author_email = '';
       
  1256 	if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) )
       
  1257 		$comment_author_email = $_COOKIE['comment_author_email_'.COOKIEHASH];
       
  1258 
       
  1259 	$comment_author_url = '';
       
  1260 	if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) )
       
  1261 		$comment_author_url = $_COOKIE['comment_author_url_'.COOKIEHASH];
       
  1262 
       
  1263 	return apply_filters('wp_get_current_commenter', compact('comment_author', 'comment_author_email', 'comment_author_url'));
       
  1264 }
       
  1265 
       
  1266 /**
       
  1267  * Inserts a comment to the database.
       
  1268  *
       
  1269  * The available comment data key names are 'comment_author_IP', 'comment_date',
       
  1270  * 'comment_date_gmt', 'comment_parent', 'comment_approved', and 'user_id'.
       
  1271  *
       
  1272  * @since 2.0.0
       
  1273  * @uses $wpdb
       
  1274  *
       
  1275  * @param array $commentdata Contains information on the comment.
       
  1276  * @return int The new comment's ID.
       
  1277  */
       
  1278 function wp_insert_comment($commentdata) {
       
  1279 	global $wpdb;
       
  1280 	extract(wp_unslash($commentdata), EXTR_SKIP);
       
  1281 
       
  1282 	if ( ! isset($comment_author_IP) )
       
  1283 		$comment_author_IP = '';
       
  1284 	if ( ! isset($comment_date) )
       
  1285 		$comment_date = current_time('mysql');
       
  1286 	if ( ! isset($comment_date_gmt) )
       
  1287 		$comment_date_gmt = get_gmt_from_date($comment_date);
       
  1288 	if ( ! isset($comment_parent) )
       
  1289 		$comment_parent = 0;
       
  1290 	if ( ! isset($comment_approved) )
       
  1291 		$comment_approved = 1;
       
  1292 	if ( ! isset($comment_karma) )
       
  1293 		$comment_karma = 0;
       
  1294 	if ( ! isset($user_id) )
       
  1295 		$user_id = 0;
       
  1296 	if ( ! isset($comment_type) )
       
  1297 		$comment_type = '';
       
  1298 
       
  1299 	$data = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id');
       
  1300 	$wpdb->insert($wpdb->comments, $data);
       
  1301 
       
  1302 	$id = (int) $wpdb->insert_id;
       
  1303 
       
  1304 	if ( $comment_approved == 1 )
       
  1305 		wp_update_comment_count($comment_post_ID);
       
  1306 
       
  1307 	$comment = get_comment($id);
       
  1308 	do_action('wp_insert_comment', $id, $comment);
       
  1309 
       
  1310 	wp_cache_set( 'last_changed', microtime(), 'comment' );
       
  1311 
       
  1312 	return $id;
       
  1313 }
       
  1314 
       
  1315 /**
       
  1316  * Filters and sanitizes comment data.
       
  1317  *
       
  1318  * Sets the comment data 'filtered' field to true when finished. This can be
       
  1319  * checked as to whether the comment should be filtered and to keep from
       
  1320  * filtering the same comment more than once.
       
  1321  *
       
  1322  * @since 2.0.0
       
  1323  * @uses apply_filters() Calls 'pre_user_id' hook on comment author's user ID
       
  1324  * @uses apply_filters() Calls 'pre_comment_user_agent' hook on comment author's user agent
       
  1325  * @uses apply_filters() Calls 'pre_comment_author_name' hook on comment author's name
       
  1326  * @uses apply_filters() Calls 'pre_comment_content' hook on the comment's content
       
  1327  * @uses apply_filters() Calls 'pre_comment_user_ip' hook on comment author's IP
       
  1328  * @uses apply_filters() Calls 'pre_comment_author_url' hook on comment author's URL
       
  1329  * @uses apply_filters() Calls 'pre_comment_author_email' hook on comment author's email address
       
  1330  *
       
  1331  * @param array $commentdata Contains information on the comment.
       
  1332  * @return array Parsed comment information.
       
  1333  */
       
  1334 function wp_filter_comment($commentdata) {
       
  1335 	if ( isset($commentdata['user_ID']) )
       
  1336 		$commentdata['user_id'] = apply_filters('pre_user_id', $commentdata['user_ID']);
       
  1337 	elseif ( isset($commentdata['user_id']) )
       
  1338 		$commentdata['user_id'] = apply_filters('pre_user_id', $commentdata['user_id']);
       
  1339 	$commentdata['comment_agent']        = apply_filters('pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) );
       
  1340 	$commentdata['comment_author']       = apply_filters('pre_comment_author_name', $commentdata['comment_author']);
       
  1341 	$commentdata['comment_content']      = apply_filters('pre_comment_content', $commentdata['comment_content']);
       
  1342 	$commentdata['comment_author_IP']    = apply_filters('pre_comment_user_ip', $commentdata['comment_author_IP']);
       
  1343 	$commentdata['comment_author_url']   = apply_filters('pre_comment_author_url', $commentdata['comment_author_url']);
       
  1344 	$commentdata['comment_author_email'] = apply_filters('pre_comment_author_email', $commentdata['comment_author_email']);
       
  1345 	$commentdata['filtered'] = true;
       
  1346 	return $commentdata;
       
  1347 }
       
  1348 
       
  1349 /**
       
  1350  * Whether comment should be blocked because of comment flood.
       
  1351  *
       
  1352  * @since 2.1.0
       
  1353  *
       
  1354  * @param bool $block Whether plugin has already blocked comment.
       
  1355  * @param int $time_lastcomment Timestamp for last comment.
       
  1356  * @param int $time_newcomment Timestamp for new comment.
       
  1357  * @return bool Whether comment should be blocked.
       
  1358  */
       
  1359 function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment) {
       
  1360 	if ( $block ) // a plugin has already blocked... we'll let that decision stand
       
  1361 		return $block;
       
  1362 	if ( ($time_newcomment - $time_lastcomment) < 15 )
       
  1363 		return true;
       
  1364 	return false;
       
  1365 }
       
  1366 
       
  1367 /**
       
  1368  * Adds a new comment to the database.
       
  1369  *
       
  1370  * Filters new comment to ensure that the fields are sanitized and valid before
       
  1371  * inserting comment into database. Calls 'comment_post' action with comment ID
       
  1372  * and whether comment is approved by WordPress. Also has 'preprocess_comment'
       
  1373  * filter for processing the comment data before the function handles it.
       
  1374  *
       
  1375  * We use REMOTE_ADDR here directly. If you are behind a proxy, you should ensure
       
  1376  * that it is properly set, such as in wp-config.php, for your environment.
       
  1377  * See {@link http://core.trac.wordpress.org/ticket/9235}
       
  1378  *
       
  1379  * @since 1.5.0
       
  1380  * @uses apply_filters() Calls 'preprocess_comment' hook on $commentdata parameter array before processing
       
  1381  * @uses do_action() Calls 'comment_post' hook on $comment_ID returned from adding the comment and if the comment was approved.
       
  1382  * @uses wp_filter_comment() Used to filter comment before adding comment.
       
  1383  * @uses wp_allow_comment() checks to see if comment is approved.
       
  1384  * @uses wp_insert_comment() Does the actual comment insertion to the database.
       
  1385  *
       
  1386  * @param array $commentdata Contains information on the comment.
       
  1387  * @return int The ID of the comment after adding.
       
  1388  */
       
  1389 function wp_new_comment( $commentdata ) {
       
  1390 	$commentdata = apply_filters('preprocess_comment', $commentdata);
       
  1391 
       
  1392 	$commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
       
  1393 	if ( isset($commentdata['user_ID']) )
       
  1394 		$commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
       
  1395 	elseif ( isset($commentdata['user_id']) )
       
  1396 		$commentdata['user_id'] = (int) $commentdata['user_id'];
       
  1397 
       
  1398 	$commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
       
  1399 	$parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
       
  1400 	$commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
       
  1401 
       
  1402 	$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] );
       
  1403 	$commentdata['comment_agent']     = isset( $_SERVER['HTTP_USER_AGENT'] ) ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : '';
       
  1404 
       
  1405 	$commentdata['comment_date']     = current_time('mysql');
       
  1406 	$commentdata['comment_date_gmt'] = current_time('mysql', 1);
       
  1407 
       
  1408 	$commentdata = wp_filter_comment($commentdata);
       
  1409 
       
  1410 	$commentdata['comment_approved'] = wp_allow_comment($commentdata);
       
  1411 
       
  1412 	$comment_ID = wp_insert_comment($commentdata);
       
  1413 
       
  1414 	do_action('comment_post', $comment_ID, $commentdata['comment_approved']);
       
  1415 
       
  1416 	if ( 'spam' !== $commentdata['comment_approved'] ) { // If it's spam save it silently for later crunching
       
  1417 		if ( '0' == $commentdata['comment_approved'] )
       
  1418 			wp_notify_moderator($comment_ID);
       
  1419 
       
  1420 		$post = get_post($commentdata['comment_post_ID']); // Don't notify if it's your own comment
       
  1421 
       
  1422 		if ( get_option('comments_notify') && $commentdata['comment_approved'] && ( ! isset( $commentdata['user_id'] ) || $post->post_author != $commentdata['user_id'] ) )
       
  1423 			wp_notify_postauthor($comment_ID, isset( $commentdata['comment_type'] ) ? $commentdata['comment_type'] : '' );
       
  1424 	}
       
  1425 
       
  1426 	return $comment_ID;
       
  1427 }
       
  1428 
       
  1429 /**
       
  1430  * Sets the status of a comment.
       
  1431  *
       
  1432  * The 'wp_set_comment_status' action is called after the comment is handled.
       
  1433  * If the comment status is not in the list, then false is returned.
       
  1434  *
       
  1435  * @since 1.0.0
       
  1436  * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
       
  1437  *
       
  1438  * @param int $comment_id Comment ID.
       
  1439  * @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
       
  1440  * @param bool $wp_error Whether to return a WP_Error object if there is a failure. Default is false.
       
  1441  * @return bool|WP_Error True on success, false or WP_Error on failure.
       
  1442  */
       
  1443 function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
       
  1444 	global $wpdb;
       
  1445 
       
  1446 	$status = '0';
       
  1447 	switch ( $comment_status ) {
       
  1448 		case 'hold':
       
  1449 		case '0':
       
  1450 			$status = '0';
       
  1451 			break;
       
  1452 		case 'approve':
       
  1453 		case '1':
       
  1454 			$status = '1';
       
  1455 			if ( get_option('comments_notify') ) {
       
  1456 				$comment = get_comment($comment_id);
       
  1457 				wp_notify_postauthor($comment_id, $comment->comment_type);
       
  1458 			}
       
  1459 			break;
       
  1460 		case 'spam':
       
  1461 			$status = 'spam';
       
  1462 			break;
       
  1463 		case 'trash':
       
  1464 			$status = 'trash';
       
  1465 			break;
       
  1466 		default:
       
  1467 			return false;
       
  1468 	}
       
  1469 
       
  1470 	$comment_old = clone get_comment($comment_id);
       
  1471 
       
  1472 	if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array('comment_ID' => $comment_id) ) ) {
       
  1473 		if ( $wp_error )
       
  1474 			return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
       
  1475 		else
       
  1476 			return false;
       
  1477 	}
       
  1478 
       
  1479 	clean_comment_cache($comment_id);
       
  1480 
       
  1481 	$comment = get_comment($comment_id);
       
  1482 
       
  1483 	do_action('wp_set_comment_status', $comment_id, $comment_status);
       
  1484 	wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
       
  1485 
       
  1486 	wp_update_comment_count($comment->comment_post_ID);
       
  1487 
       
  1488 	return true;
       
  1489 }
       
  1490 
       
  1491 /**
       
  1492  * Updates an existing comment in the database.
       
  1493  *
       
  1494  * Filters the comment and makes sure certain fields are valid before updating.
       
  1495  *
       
  1496  * @since 2.0.0
       
  1497  * @uses $wpdb
       
  1498  * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
       
  1499  *
       
  1500  * @param array $commentarr Contains information on the comment.
       
  1501  * @return int Comment was updated if value is 1, or was not updated if value is 0.
       
  1502  */
       
  1503 function wp_update_comment($commentarr) {
       
  1504 	global $wpdb;
       
  1505 
       
  1506 	// First, get all of the original fields
       
  1507 	$comment = get_comment($commentarr['comment_ID'], ARRAY_A);
       
  1508 	if ( empty( $comment ) )
       
  1509 		return 0;
       
  1510 
       
  1511 	// Escape data pulled from DB.
       
  1512 	$comment = wp_slash($comment);
       
  1513 
       
  1514 	$old_status = $comment['comment_approved'];
       
  1515 
       
  1516 	// Merge old and new fields with new fields overwriting old ones.
       
  1517 	$commentarr = array_merge($comment, $commentarr);
       
  1518 
       
  1519 	$commentarr = wp_filter_comment( $commentarr );
       
  1520 
       
  1521 	// Now extract the merged array.
       
  1522 	extract(wp_unslash($commentarr), EXTR_SKIP);
       
  1523 
       
  1524 	$comment_content = apply_filters('comment_save_pre', $comment_content);
       
  1525 
       
  1526 	$comment_date_gmt = get_gmt_from_date($comment_date);
       
  1527 
       
  1528 	if ( !isset($comment_approved) )
       
  1529 		$comment_approved = 1;
       
  1530 	else if ( 'hold' == $comment_approved )
       
  1531 		$comment_approved = 0;
       
  1532 	else if ( 'approve' == $comment_approved )
       
  1533 		$comment_approved = 1;
       
  1534 
       
  1535 	$data = compact( 'comment_content', 'comment_author', 'comment_author_email', 'comment_approved', 'comment_karma', 'comment_author_url', 'comment_date', 'comment_date_gmt', 'comment_parent' );
       
  1536 	$rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
       
  1537 
       
  1538 	clean_comment_cache($comment_ID);
       
  1539 	wp_update_comment_count($comment_post_ID);
       
  1540 	do_action('edit_comment', $comment_ID);
       
  1541 	$comment = get_comment($comment_ID);
       
  1542 	wp_transition_comment_status($comment->comment_approved, $old_status, $comment);
       
  1543 	return $rval;
       
  1544 }
       
  1545 
       
  1546 /**
       
  1547  * Whether to defer comment counting.
       
  1548  *
       
  1549  * When setting $defer to true, all post comment counts will not be updated
       
  1550  * until $defer is set to false. When $defer is set to false, then all
       
  1551  * previously deferred updated post comment counts will then be automatically
       
  1552  * updated without having to call wp_update_comment_count() after.
       
  1553  *
       
  1554  * @since 2.5.0
       
  1555  * @staticvar bool $_defer
       
  1556  *
       
  1557  * @param bool $defer
       
  1558  * @return unknown
       
  1559  */
       
  1560 function wp_defer_comment_counting($defer=null) {
       
  1561 	static $_defer = false;
       
  1562 
       
  1563 	if ( is_bool($defer) ) {
       
  1564 		$_defer = $defer;
       
  1565 		// flush any deferred counts
       
  1566 		if ( !$defer )
       
  1567 			wp_update_comment_count( null, true );
       
  1568 	}
       
  1569 
       
  1570 	return $_defer;
       
  1571 }
       
  1572 
       
  1573 /**
       
  1574  * Updates the comment count for post(s).
       
  1575  *
       
  1576  * When $do_deferred is false (is by default) and the comments have been set to
       
  1577  * be deferred, the post_id will be added to a queue, which will be updated at a
       
  1578  * later date and only updated once per post ID.
       
  1579  *
       
  1580  * If the comments have not be set up to be deferred, then the post will be
       
  1581  * updated. When $do_deferred is set to true, then all previous deferred post
       
  1582  * IDs will be updated along with the current $post_id.
       
  1583  *
       
  1584  * @since 2.1.0
       
  1585  * @see wp_update_comment_count_now() For what could cause a false return value
       
  1586  *
       
  1587  * @param int $post_id Post ID
       
  1588  * @param bool $do_deferred Whether to process previously deferred post comment counts
       
  1589  * @return bool True on success, false on failure
       
  1590  */
       
  1591 function wp_update_comment_count($post_id, $do_deferred=false) {
       
  1592 	static $_deferred = array();
       
  1593 
       
  1594 	if ( $do_deferred ) {
       
  1595 		$_deferred = array_unique($_deferred);
       
  1596 		foreach ( $_deferred as $i => $_post_id ) {
       
  1597 			wp_update_comment_count_now($_post_id);
       
  1598 			unset( $_deferred[$i] ); /** @todo Move this outside of the foreach and reset $_deferred to an array instead */
       
  1599 		}
       
  1600 	}
       
  1601 
       
  1602 	if ( wp_defer_comment_counting() ) {
       
  1603 		$_deferred[] = $post_id;
       
  1604 		return true;
       
  1605 	}
       
  1606 	elseif ( $post_id ) {
       
  1607 		return wp_update_comment_count_now($post_id);
       
  1608 	}
       
  1609 
       
  1610 }
       
  1611 
       
  1612 /**
       
  1613  * Updates the comment count for the post.
       
  1614  *
       
  1615  * @since 2.5.0
       
  1616  * @uses $wpdb
       
  1617  * @uses do_action() Calls 'wp_update_comment_count' hook on $post_id, $new, and $old
       
  1618  * @uses do_action() Calls 'edit_posts' hook on $post_id and $post
       
  1619  *
       
  1620  * @param int $post_id Post ID
       
  1621  * @return bool True on success, false on '0' $post_id or if post with ID does not exist.
       
  1622  */
       
  1623 function wp_update_comment_count_now($post_id) {
       
  1624 	global $wpdb;
       
  1625 	$post_id = (int) $post_id;
       
  1626 	if ( !$post_id )
       
  1627 		return false;
       
  1628 	if ( !$post = get_post($post_id) )
       
  1629 		return false;
       
  1630 
       
  1631 	$old = (int) $post->comment_count;
       
  1632 	$new = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id) );
       
  1633 	$wpdb->update( $wpdb->posts, array('comment_count' => $new), array('ID' => $post_id) );
       
  1634 
       
  1635 	clean_post_cache( $post );
       
  1636 
       
  1637 	do_action('wp_update_comment_count', $post_id, $new, $old);
       
  1638 	do_action('edit_post', $post_id, $post);
       
  1639 
       
  1640 	return true;
       
  1641 }
       
  1642 
       
  1643 //
       
  1644 // Ping and trackback functions.
       
  1645 //
       
  1646 
       
  1647 /**
       
  1648  * Finds a pingback server URI based on the given URL.
       
  1649  *
       
  1650  * Checks the HTML for the rel="pingback" link and x-pingback headers. It does
       
  1651  * a check for the x-pingback headers first and returns that, if available. The
       
  1652  * check for the rel="pingback" has more overhead than just the header.
       
  1653  *
       
  1654  * @since 1.5.0
       
  1655  *
       
  1656  * @param string $url URL to ping.
       
  1657  * @param int $deprecated Not Used.
       
  1658  * @return bool|string False on failure, string containing URI on success.
       
  1659  */
       
  1660 function discover_pingback_server_uri( $url, $deprecated = '' ) {
       
  1661 	if ( !empty( $deprecated ) )
       
  1662 		_deprecated_argument( __FUNCTION__, '2.7' );
       
  1663 
       
  1664 	$pingback_str_dquote = 'rel="pingback"';
       
  1665 	$pingback_str_squote = 'rel=\'pingback\'';
       
  1666 
       
  1667 	/** @todo Should use Filter Extension or custom preg_match instead. */
       
  1668 	$parsed_url = parse_url($url);
       
  1669 
       
  1670 	if ( ! isset( $parsed_url['host'] ) ) // Not an URL. This should never happen.
       
  1671 		return false;
       
  1672 
       
  1673 	//Do not search for a pingback server on our own uploads
       
  1674 	$uploads_dir = wp_upload_dir();
       
  1675 	if ( 0 === strpos($url, $uploads_dir['baseurl']) )
       
  1676 		return false;
       
  1677 
       
  1678 	$response = wp_safe_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
       
  1679 
       
  1680 	if ( is_wp_error( $response ) )
       
  1681 		return false;
       
  1682 
       
  1683 	if ( wp_remote_retrieve_header( $response, 'x-pingback' ) )
       
  1684 		return wp_remote_retrieve_header( $response, 'x-pingback' );
       
  1685 
       
  1686 	// Not an (x)html, sgml, or xml page, no use going further.
       
  1687 	if ( preg_match('#(image|audio|video|model)/#is', wp_remote_retrieve_header( $response, 'content-type' )) )
       
  1688 		return false;
       
  1689 
       
  1690 	// Now do a GET since we're going to look in the html headers (and we're sure it's not a binary file)
       
  1691 	$response = wp_safe_remote_get( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
       
  1692 
       
  1693 	if ( is_wp_error( $response ) )
       
  1694 		return false;
       
  1695 
       
  1696 	$contents = wp_remote_retrieve_body( $response );
       
  1697 
       
  1698 	$pingback_link_offset_dquote = strpos($contents, $pingback_str_dquote);
       
  1699 	$pingback_link_offset_squote = strpos($contents, $pingback_str_squote);
       
  1700 	if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
       
  1701 		$quote = ($pingback_link_offset_dquote) ? '"' : '\'';
       
  1702 		$pingback_link_offset = ($quote=='"') ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
       
  1703 		$pingback_href_pos = @strpos($contents, 'href=', $pingback_link_offset);
       
  1704 		$pingback_href_start = $pingback_href_pos+6;
       
  1705 		$pingback_href_end = @strpos($contents, $quote, $pingback_href_start);
       
  1706 		$pingback_server_url_len = $pingback_href_end - $pingback_href_start;
       
  1707 		$pingback_server_url = substr($contents, $pingback_href_start, $pingback_server_url_len);
       
  1708 
       
  1709 		// We may find rel="pingback" but an incomplete pingback URL
       
  1710 		if ( $pingback_server_url_len > 0 ) { // We got it!
       
  1711 			return $pingback_server_url;
       
  1712 		}
       
  1713 	}
       
  1714 
       
  1715 	return false;
       
  1716 }
       
  1717 
       
  1718 /**
       
  1719  * Perform all pingbacks, enclosures, trackbacks, and send to pingback services.
       
  1720  *
       
  1721  * @since 2.1.0
       
  1722  * @uses $wpdb
       
  1723  */
       
  1724 function do_all_pings() {
       
  1725 	global $wpdb;
       
  1726 
       
  1727 	// Do pingbacks
       
  1728 	while ($ping = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_pingme' LIMIT 1")) {
       
  1729 		delete_metadata_by_mid( 'post', $ping->meta_id );
       
  1730 		pingback( $ping->post_content, $ping->ID );
       
  1731 	}
       
  1732 
       
  1733 	// Do Enclosures
       
  1734 	while ($enclosure = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1")) {
       
  1735 		delete_metadata_by_mid( 'post', $enclosure->meta_id );
       
  1736 		do_enclose( $enclosure->post_content, $enclosure->ID );
       
  1737 	}
       
  1738 
       
  1739 	// Do Trackbacks
       
  1740 	$trackbacks = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE to_ping <> '' AND post_status = 'publish'");
       
  1741 	if ( is_array($trackbacks) )
       
  1742 		foreach ( $trackbacks as $trackback )
       
  1743 			do_trackbacks($trackback);
       
  1744 
       
  1745 	//Do Update Services/Generic Pings
       
  1746 	generic_ping();
       
  1747 }
       
  1748 
       
  1749 /**
       
  1750  * Perform trackbacks.
       
  1751  *
       
  1752  * @since 1.5.0
       
  1753  * @uses $wpdb
       
  1754  *
       
  1755  * @param int $post_id Post ID to do trackbacks on.
       
  1756  */
       
  1757 function do_trackbacks($post_id) {
       
  1758 	global $wpdb;
       
  1759 
       
  1760 	$post = get_post( $post_id );
       
  1761 	$to_ping = get_to_ping($post_id);
       
  1762 	$pinged  = get_pung($post_id);
       
  1763 	if ( empty($to_ping) ) {
       
  1764 		$wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
       
  1765 		return;
       
  1766 	}
       
  1767 
       
  1768 	if ( empty($post->post_excerpt) )
       
  1769 		$excerpt = apply_filters('the_content', $post->post_content, $post->ID);
       
  1770 	else
       
  1771 		$excerpt = apply_filters('the_excerpt', $post->post_excerpt);
       
  1772 	$excerpt = str_replace(']]>', ']]&gt;', $excerpt);
       
  1773 	$excerpt = wp_html_excerpt($excerpt, 252, '&#8230;');
       
  1774 
       
  1775 	/** This filter is documented in wp-includes/post-template.php */
       
  1776 	$post_title = apply_filters('the_title', $post->post_title, $post->ID);
       
  1777 	$post_title = strip_tags($post_title);
       
  1778 
       
  1779 	if ( $to_ping ) {
       
  1780 		foreach ( (array) $to_ping as $tb_ping ) {
       
  1781 			$tb_ping = trim($tb_ping);
       
  1782 			if ( !in_array($tb_ping, $pinged) ) {
       
  1783 				trackback($tb_ping, $post_title, $excerpt, $post_id);
       
  1784 				$pinged[] = $tb_ping;
       
  1785 			} else {
       
  1786 				$wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post_id) );
       
  1787 			}
       
  1788 		}
       
  1789 	}
       
  1790 }
       
  1791 
       
  1792 /**
       
  1793  * Sends pings to all of the ping site services.
       
  1794  *
       
  1795  * @since 1.2.0
       
  1796  *
       
  1797  * @param int $post_id Post ID. Not actually used.
       
  1798  * @return int Same as Post ID from parameter
       
  1799  */
       
  1800 function generic_ping($post_id = 0) {
       
  1801 	$services = get_option('ping_sites');
       
  1802 
       
  1803 	$services = explode("\n", $services);
       
  1804 	foreach ( (array) $services as $service ) {
       
  1805 		$service = trim($service);
       
  1806 		if ( '' != $service )
       
  1807 			weblog_ping($service);
       
  1808 	}
       
  1809 
       
  1810 	return $post_id;
       
  1811 }
       
  1812 
       
  1813 /**
       
  1814  * Pings back the links found in a post.
       
  1815  *
       
  1816  * @since 0.71
       
  1817  * @uses $wp_version
       
  1818  * @uses IXR_Client
       
  1819  *
       
  1820  * @param string $content Post content to check for links.
       
  1821  * @param int $post_ID Post ID.
       
  1822  */
       
  1823 function pingback($content, $post_ID) {
       
  1824 	global $wp_version;
       
  1825 	include_once(ABSPATH . WPINC . '/class-IXR.php');
       
  1826 	include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
       
  1827 
       
  1828 	// original code by Mort (http://mort.mine.nu:8080)
       
  1829 	$post_links = array();
       
  1830 
       
  1831 	$pung = get_pung($post_ID);
       
  1832 
       
  1833 	// Step 1
       
  1834 	// Parsing the post, external links (if any) are stored in the $post_links array
       
  1835 	$post_links_temp = wp_extract_urls( $content );
       
  1836 
       
  1837 	// Step 2.
       
  1838 	// Walking thru the links array
       
  1839 	// first we get rid of links pointing to sites, not to specific files
       
  1840 	// Example:
       
  1841 	// http://dummy-weblog.org
       
  1842 	// http://dummy-weblog.org/
       
  1843 	// http://dummy-weblog.org/post.php
       
  1844 	// We don't wanna ping first and second types, even if they have a valid <link/>
       
  1845 
       
  1846 	foreach ( (array) $post_links_temp as $link_test ) :
       
  1847 		if ( !in_array($link_test, $pung) && (url_to_postid($link_test) != $post_ID) // If we haven't pung it already and it isn't a link to itself
       
  1848 				&& !is_local_attachment($link_test) ) : // Also, let's never ping local attachments.
       
  1849 			if ( $test = @parse_url($link_test) ) {
       
  1850 				if ( isset($test['query']) )
       
  1851 					$post_links[] = $link_test;
       
  1852 				elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) )
       
  1853 					$post_links[] = $link_test;
       
  1854 			}
       
  1855 		endif;
       
  1856 	endforeach;
       
  1857 
       
  1858 	$post_links = array_unique( $post_links );
       
  1859 	do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post_ID ) );
       
  1860 
       
  1861 	foreach ( (array) $post_links as $pagelinkedto ) {
       
  1862 		$pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
       
  1863 
       
  1864 		if ( $pingback_server_url ) {
       
  1865 			@ set_time_limit( 60 );
       
  1866 			 // Now, the RPC call
       
  1867 			$pagelinkedfrom = get_permalink($post_ID);
       
  1868 
       
  1869 			// using a timeout of 3 seconds should be enough to cover slow servers
       
  1870 			$client = new WP_HTTP_IXR_Client($pingback_server_url);
       
  1871 			$client->timeout = 3;
       
  1872 			$client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . $wp_version, $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom);
       
  1873 			// when set to true, this outputs debug messages by itself
       
  1874 			$client->debug = false;
       
  1875 
       
  1876 			if ( $client->query('pingback.ping', $pagelinkedfrom, $pagelinkedto) || ( isset($client->error->code) && 48 == $client->error->code ) ) // Already registered
       
  1877 				add_ping( $post_ID, $pagelinkedto );
       
  1878 		}
       
  1879 	}
       
  1880 }
       
  1881 
       
  1882 /**
       
  1883  * Check whether blog is public before returning sites.
       
  1884  *
       
  1885  * @since 2.1.0
       
  1886  *
       
  1887  * @param mixed $sites Will return if blog is public, will not return if not public.
       
  1888  * @return mixed Empty string if blog is not public, returns $sites, if site is public.
       
  1889  */
       
  1890 function privacy_ping_filter($sites) {
       
  1891 	if ( '0' != get_option('blog_public') )
       
  1892 		return $sites;
       
  1893 	else
       
  1894 		return '';
       
  1895 }
       
  1896 
       
  1897 /**
       
  1898  * Send a Trackback.
       
  1899  *
       
  1900  * Updates database when sending trackback to prevent duplicates.
       
  1901  *
       
  1902  * @since 0.71
       
  1903  * @uses $wpdb
       
  1904  *
       
  1905  * @param string $trackback_url URL to send trackbacks.
       
  1906  * @param string $title Title of post.
       
  1907  * @param string $excerpt Excerpt of post.
       
  1908  * @param int $ID Post ID.
       
  1909  * @return mixed Database query from update.
       
  1910  */
       
  1911 function trackback($trackback_url, $title, $excerpt, $ID) {
       
  1912 	global $wpdb;
       
  1913 
       
  1914 	if ( empty($trackback_url) )
       
  1915 		return;
       
  1916 
       
  1917 	$options = array();
       
  1918 	$options['timeout'] = 4;
       
  1919 	$options['body'] = array(
       
  1920 		'title' => $title,
       
  1921 		'url' => get_permalink($ID),
       
  1922 		'blog_name' => get_option('blogname'),
       
  1923 		'excerpt' => $excerpt
       
  1924 	);
       
  1925 
       
  1926 	$response = wp_safe_remote_post( $trackback_url, $options );
       
  1927 
       
  1928 	if ( is_wp_error( $response ) )
       
  1929 		return;
       
  1930 
       
  1931 	$wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $ID) );
       
  1932 	return $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $ID) );
       
  1933 }
       
  1934 
       
  1935 /**
       
  1936  * Send a pingback.
       
  1937  *
       
  1938  * @since 1.2.0
       
  1939  * @uses $wp_version
       
  1940  * @uses IXR_Client
       
  1941  *
       
  1942  * @param string $server Host of blog to connect to.
       
  1943  * @param string $path Path to send the ping.
       
  1944  */
       
  1945 function weblog_ping($server = '', $path = '') {
       
  1946 	global $wp_version;
       
  1947 	include_once(ABSPATH . WPINC . '/class-IXR.php');
       
  1948 	include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
       
  1949 
       
  1950 	// using a timeout of 3 seconds should be enough to cover slow servers
       
  1951 	$client = new WP_HTTP_IXR_Client($server, ((!strlen(trim($path)) || ('/' == $path)) ? false : $path));
       
  1952 	$client->timeout = 3;
       
  1953 	$client->useragent .= ' -- WordPress/'.$wp_version;
       
  1954 
       
  1955 	// when set to true, this outputs debug messages by itself
       
  1956 	$client->debug = false;
       
  1957 	$home = trailingslashit( home_url() );
       
  1958 	if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
       
  1959 		$client->query('weblogUpdates.ping', get_option('blogname'), $home);
       
  1960 }
       
  1961 
       
  1962 /**
       
  1963  * Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI
       
  1964  *
       
  1965  * @since 3.5.1
       
  1966  * @see wp_http_validate_url()
       
  1967  *
       
  1968  * @param string $source_uri
       
  1969  * @return string
       
  1970  */
       
  1971 function pingback_ping_source_uri( $source_uri ) {
       
  1972 	return (string) wp_http_validate_url( $source_uri );
       
  1973 }
       
  1974 
       
  1975 /**
       
  1976  * Default filter attached to xmlrpc_pingback_error.
       
  1977  *
       
  1978  * Returns a generic pingback error code unless the error code is 48,
       
  1979  * which reports that the pingback is already registered.
       
  1980  *
       
  1981  * @since 3.5.1
       
  1982  * @link http://www.hixie.ch/specs/pingback/pingback#TOC3
       
  1983  *
       
  1984  * @param IXR_Error $ixr_error
       
  1985  * @return IXR_Error
       
  1986  */
       
  1987 function xmlrpc_pingback_error( $ixr_error ) {
       
  1988 	if ( $ixr_error->code === 48 )
       
  1989 		return $ixr_error;
       
  1990 	return new IXR_Error( 0, '' );
       
  1991 }
       
  1992 
       
  1993 //
       
  1994 // Cache
       
  1995 //
       
  1996 
       
  1997 /**
       
  1998  * Removes comment ID from the comment cache.
       
  1999  *
       
  2000  * @since 2.3.0
       
  2001  * @package WordPress
       
  2002  * @subpackage Cache
       
  2003  *
       
  2004  * @param int|array $ids Comment ID or array of comment IDs to remove from cache
       
  2005  */
       
  2006 function clean_comment_cache($ids) {
       
  2007 	foreach ( (array) $ids as $id )
       
  2008 		wp_cache_delete($id, 'comment');
       
  2009 
       
  2010 	wp_cache_set( 'last_changed', microtime(), 'comment' );
       
  2011 }
       
  2012 
       
  2013 /**
       
  2014  * Updates the comment cache of given comments.
       
  2015  *
       
  2016  * Will add the comments in $comments to the cache. If comment ID already exists
       
  2017  * in the comment cache then it will not be updated. The comment is added to the
       
  2018  * cache using the comment group with the key using the ID of the comments.
       
  2019  *
       
  2020  * @since 2.3.0
       
  2021  * @package WordPress
       
  2022  * @subpackage Cache
       
  2023  *
       
  2024  * @param array $comments Array of comment row objects
       
  2025  */
       
  2026 function update_comment_cache($comments) {
       
  2027 	foreach ( (array) $comments as $comment )
       
  2028 		wp_cache_add($comment->comment_ID, $comment, 'comment');
       
  2029 }
       
  2030 
       
  2031 //
       
  2032 // Internal
       
  2033 //
       
  2034 
       
  2035 /**
       
  2036  * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
       
  2037  *
       
  2038  * @access private
       
  2039  * @since 2.7.0
       
  2040  *
       
  2041  * @param object $posts Post data object.
       
  2042  * @param object $query Query object.
       
  2043  * @return object
       
  2044  */
       
  2045 function _close_comments_for_old_posts( $posts, $query ) {
       
  2046 	if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) )
       
  2047 		return $posts;
       
  2048 
       
  2049 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
       
  2050 	if ( ! in_array( $posts[0]->post_type, $post_types ) )
       
  2051 		return $posts;
       
  2052 
       
  2053 	$days_old = (int) get_option( 'close_comments_days_old' );
       
  2054 	if ( ! $days_old )
       
  2055 		return $posts;
       
  2056 
       
  2057 	if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) ) {
       
  2058 		$posts[0]->comment_status = 'closed';
       
  2059 		$posts[0]->ping_status = 'closed';
       
  2060 	}
       
  2061 
       
  2062 	return $posts;
       
  2063 }
       
  2064 
       
  2065 /**
       
  2066  * Close comments on an old post. Hooked to comments_open and pings_open.
       
  2067  *
       
  2068  * @access private
       
  2069  * @since 2.7.0
       
  2070  *
       
  2071  * @param bool $open Comments open or closed
       
  2072  * @param int $post_id Post ID
       
  2073  * @return bool $open
       
  2074  */
       
  2075 function _close_comments_for_old_post( $open, $post_id ) {
       
  2076 	if ( ! $open )
       
  2077 		return $open;
       
  2078 
       
  2079 	if ( !get_option('close_comments_for_old_posts') )
       
  2080 		return $open;
       
  2081 
       
  2082 	$days_old = (int) get_option('close_comments_days_old');
       
  2083 	if ( !$days_old )
       
  2084 		return $open;
       
  2085 
       
  2086 	$post = get_post($post_id);
       
  2087 
       
  2088 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
       
  2089 	if ( ! in_array( $post->post_type, $post_types ) )
       
  2090 		return $open;
       
  2091 
       
  2092 	if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
       
  2093 		return false;
       
  2094 
       
  2095 	return $open;
       
  2096 }