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