Wordpress 4.6
[autoinstalls/wordpress.git] / wp-includes / comment-template.php
1 <?php
2 /**
3  * Comment template functions
4  *
5  * These functions are meant to live inside of the WordPress loop.
6  *
7  * @package WordPress
8  * @subpackage Template
9  */
10
11 /**
12  * Retrieve the author of the current comment.
13  *
14  * If the comment has an empty comment_author field, then 'Anonymous' person is
15  * assumed.
16  *
17  * @since 1.5.0
18  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
19  *
20  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to retrieve the author.
21  *                                                                       Default current comment.
22  * @return string The comment author
23  */
24 function get_comment_author( $comment_ID = 0 ) {
25         $comment = get_comment( $comment_ID );
26
27         if ( empty( $comment->comment_author ) ) {
28                 if ( $comment->user_id && $user = get_userdata( $comment->user_id ) )
29                         $author = $user->display_name;
30                 else
31                         $author = __('Anonymous');
32         } else {
33                 $author = $comment->comment_author;
34         }
35
36         /**
37          * Filters the returned comment author name.
38          *
39          * @since 1.5.0
40          * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added.
41          *
42          * @param string     $author     The comment author's username.
43          * @param int        $comment_ID The comment ID.
44          * @param WP_Comment $comment    The comment object.
45          */
46         return apply_filters( 'get_comment_author', $author, $comment->comment_ID, $comment );
47 }
48
49 /**
50  * Displays the author of the current comment.
51  *
52  * @since 0.71
53  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
54  *
55  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author.
56  *                                                                       Default current comment.
57  */
58 function comment_author( $comment_ID = 0 ) {
59         $comment = get_comment( $comment_ID );
60         $author  = get_comment_author( $comment );
61
62         /**
63          * Filters the comment author's name for display.
64          *
65          * @since 1.2.0
66          * @since 4.1.0 The `$comment_ID` parameter was added.
67          *
68          * @param string $author     The comment author's username.
69          * @param int    $comment_ID The comment ID.
70          */
71         echo apply_filters( 'comment_author', $author, $comment->comment_ID );
72 }
73
74 /**
75  * Retrieve the email of the author of the current comment.
76  *
77  * @since 1.5.0
78  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
79  *
80  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's email.
81  *                                                                       Default current comment.
82  * @return string The current comment author's email
83  */
84 function get_comment_author_email( $comment_ID = 0 ) {
85         $comment = get_comment( $comment_ID );
86
87         /**
88          * Filters the comment author's returned email address.
89          *
90          * @since 1.5.0
91          * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added.
92          *
93          * @param string     $comment_author_email The comment author's email address.
94          * @param int        $comment_ID           The comment ID.
95          * @param WP_Comment $comment              The comment object.
96          */
97         return apply_filters( 'get_comment_author_email', $comment->comment_author_email, $comment->comment_ID, $comment );
98 }
99
100 /**
101  * Display the email of the author of the current global $comment.
102  *
103  * Care should be taken to protect the email address and assure that email
104  * harvesters do not capture your commentors' email address. Most assume that
105  * their email address will not appear in raw form on the site. Doing so will
106  * enable anyone, including those that people don't want to get the email
107  * address and use it for their own means good and bad.
108  *
109  * @since 0.71
110  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
111  *
112  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's email.
113  *                                                                       Default current comment.
114  */
115 function comment_author_email( $comment_ID = 0 ) {
116         $comment      = get_comment( $comment_ID );
117         $author_email = get_comment_author_email( $comment );
118
119         /**
120          * Filters the comment author's email for display.
121          *
122          * @since 1.2.0
123          * @since 4.1.0 The `$comment_ID` parameter was added.
124          *
125          * @param string $author_email The comment author's email address.
126          * @param int    $comment_ID   The comment ID.
127          */
128         echo apply_filters( 'author_email', $author_email, $comment->comment_ID );
129 }
130
131 /**
132  * Display the html email link to the author of the current comment.
133  *
134  * Care should be taken to protect the email address and assure that email
135  * harvesters do not capture your commentors' email address. Most assume that
136  * their email address will not appear in raw form on the site. Doing so will
137  * enable anyone, including those that people don't want to get the email
138  * address and use it for their own means good and bad.
139  *
140  * @since 0.71
141  * @since 4.6.0 Added the `$comment` parameter.
142  *
143  * @param string         $linktext Optional. Text to display instead of the comment author's email address.
144  *                                 Default empty.
145  * @param string         $before   Optional. Text or HTML to display before the email link. Default empty.
146  * @param string         $after    Optional. Text or HTML to display after the email link. Default empty.
147  * @param int|WP_Comment $comment  Optional. Comment ID or WP_Comment object. Default is the current comment.
148  */
149 function comment_author_email_link( $linktext = '', $before = '', $after = '', $comment = null ) {
150         if ( $link = get_comment_author_email_link( $linktext, $before, $after, $comment ) ) {
151                 echo $link;
152         }
153 }
154
155 /**
156  * Return the html email link to the author of the current comment.
157  *
158  * Care should be taken to protect the email address and assure that email
159  * harvesters do not capture your commentors' email address. Most assume that
160  * their email address will not appear in raw form on the site. Doing so will
161  * enable anyone, including those that people don't want to get the email
162  * address and use it for their own means good and bad.
163  *
164  * @since 2.7.0
165  * @since 4.6.0 Added the `$comment` parameter.
166  *
167  * @param string         $linktext Optional. Text to display instead of the comment author's email address.
168  *                                 Default empty.
169  * @param string         $before   Optional. Text or HTML to display before the email link. Default empty.
170  * @param string         $after    Optional. Text or HTML to display after the email link. Default empty.
171  * @param int|WP_Comment $comment  Optional. Comment ID or WP_Comment object. Default is the current comment.
172  * @return string HTML markup for the comment author email link. By default, the email address is obfuscated
173  *                via the {@see 'comment_email'} filter with antispambot().
174  */
175 function get_comment_author_email_link( $linktext = '', $before = '', $after = '', $comment = null ) {
176         $comment = get_comment( $comment );
177
178         /**
179          * Filters the comment author's email for display.
180          *
181          * Care should be taken to protect the email address and assure that email
182          * harvesters do not capture your commenter's email address.
183          *
184          * @since 1.2.0
185          * @since 4.1.0 The `$comment` parameter was added.
186          *
187          * @param string     $comment_author_email The comment author's email address.
188          * @param WP_Comment $comment              The comment object.
189          */
190         $email = apply_filters( 'comment_email', $comment->comment_author_email, $comment );
191
192         if ((!empty($email)) && ($email != '@')) {
193         $display = ($linktext != '') ? $linktext : $email;
194                 $return  = $before;
195                 $return .= sprintf( '<a href="%1$s">%2$s</a>', esc_url( 'mailto:' . $email ), esc_html( $display ) );
196                 $return .= $after;
197                 return $return;
198         } else {
199                 return '';
200         }
201 }
202
203 /**
204  * Retrieve the HTML link to the URL of the author of the current comment.
205  *
206  * Both get_comment_author_url() and get_comment_author() rely on get_comment(),
207  * which falls back to the global comment variable if the $comment_ID argument is empty.
208  *
209  * @since 1.5.0
210  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
211  *
212  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's link.
213  *                                                                       Default current comment.
214  * @return string The comment author name or HTML link for author's URL.
215  */
216 function get_comment_author_link( $comment_ID = 0 ) {
217         $comment = get_comment( $comment_ID );
218         $url     = get_comment_author_url( $comment );
219         $author  = get_comment_author( $comment );
220
221         if ( empty( $url ) || 'http://' == $url )
222                 $return = $author;
223         else
224                 $return = "<a href='$url' rel='external nofollow' class='url'>$author</a>";
225
226         /**
227          * Filters the comment author's link for display.
228          *
229          * @since 1.5.0
230          * @since 4.1.0 The `$author` and `$comment_ID` parameters were added.
231          *
232          * @param string $return     The HTML-formatted comment author link.
233          *                           Empty for an invalid URL.
234          * @param string $author     The comment author's username.
235          * @param int    $comment_ID The comment ID.
236          */
237         return apply_filters( 'get_comment_author_link', $return, $author, $comment->comment_ID );
238 }
239
240 /**
241  * Display the html link to the url of the author of the current comment.
242  *
243  * @since 0.71
244  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
245  *
246  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's link.
247  *                                                                       Default current comment.
248  */
249 function comment_author_link( $comment_ID = 0 ) {
250         echo get_comment_author_link( $comment_ID );
251 }
252
253 /**
254  * Retrieve the IP address of the author of the current comment.
255  *
256  * @since 1.5.0
257  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
258  *
259  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's IP address.
260  *                                                                       Default current comment.
261  * @return string Comment author's IP address.
262  */
263 function get_comment_author_IP( $comment_ID = 0 ) {
264         $comment = get_comment( $comment_ID );
265
266         /**
267          * Filters the comment author's returned IP address.
268          *
269          * @since 1.5.0
270          * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added.
271          *
272          * @param string     $comment_author_IP The comment author's IP address.
273          * @param int        $comment_ID        The comment ID.
274          * @param WP_Comment $comment           The comment object.
275          */
276         return apply_filters( 'get_comment_author_IP', $comment->comment_author_IP, $comment->comment_ID, $comment );
277 }
278
279 /**
280  * Display the IP address of the author of the current comment.
281  *
282  * @since 0.71
283  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
284  *
285  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's IP address.
286  *                                                                       Default current comment.
287  */
288 function comment_author_IP( $comment_ID = 0 ) {
289         echo esc_html( get_comment_author_IP( $comment_ID ) );
290 }
291
292 /**
293  * Retrieve the url of the author of the current comment.
294  *
295  * @since 1.5.0
296  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
297  *
298  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's URL.
299  *                                                                       Default current comment.
300  * @return string Comment author URL.
301  */
302 function get_comment_author_url( $comment_ID = 0 ) {
303         $comment = get_comment( $comment_ID );
304         $url = '';
305         $id = 0;
306         if ( ! empty( $comment ) ) {
307                 $author_url = ( 'http://' == $comment->comment_author_url ) ? '' : $comment->comment_author_url;
308                 $url = esc_url( $author_url, array( 'http', 'https' ) );
309                 $id = $comment->ID;
310         }
311
312         /**
313          * Filters the comment author's URL.
314          *
315          * @since 1.5.0
316          * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added.
317          *
318          * @param string     $url        The comment author's URL.
319          * @param int        $comment_ID The comment ID.
320          * @param WP_Comment $comment    The comment object.
321          */
322         return apply_filters( 'get_comment_author_url', $url, $id, $comment );
323 }
324
325 /**
326  * Display the url of the author of the current comment.
327  *
328  * @since 0.71
329  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
330  *
331  * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's URL.
332  *                                                                       Default current comment.
333  */
334 function comment_author_url( $comment_ID = 0 ) {
335         $comment    = get_comment( $comment_ID );
336         $author_url = get_comment_author_url( $comment );
337
338         /**
339          * Filters the comment author's URL for display.
340          *
341          * @since 1.2.0
342          * @since 4.1.0 The `$comment_ID` parameter was added.
343          *
344          * @param string $author_url The comment author's URL.
345          * @param int    $comment_ID The comment ID.
346          */
347         echo apply_filters( 'comment_url', $author_url, $comment->comment_ID );
348 }
349
350 /**
351  * Retrieves the HTML link of the url of the author of the current comment.
352  *
353  * $linktext parameter is only used if the URL does not exist for the comment
354  * author. If the URL does exist then the URL will be used and the $linktext
355  * will be ignored.
356  *
357  * Encapsulate the HTML link between the $before and $after. So it will appear
358  * in the order of $before, link, and finally $after.
359  *
360  * @since 1.5.0
361  * @since 4.6.0 Added the `$comment` parameter.
362  *
363  * @param string         $linktext Optional. The text to display instead of the comment
364  *                                 author's email address. Default empty.
365  * @param string         $before   Optional. The text or HTML to display before the email link.
366  *                                 Default empty.
367  * @param string         $after    Optional. The text or HTML to display after the email link.
368  *                                 Default empty.
369  * @param int|WP_Comment $comment  Optional. Comment ID or WP_Comment object.
370  *                                 Default is the current comment.
371  * @return string The HTML link between the $before and $after parameters.
372  */
373 function get_comment_author_url_link( $linktext = '', $before = '', $after = '', $comment = 0 ) {
374         $url = get_comment_author_url( $comment );
375         $display = ($linktext != '') ? $linktext : $url;
376         $display = str_replace( 'http://www.', '', $display );
377         $display = str_replace( 'http://', '', $display );
378
379         if ( '/' == substr($display, -1) ) {
380                 $display = substr($display, 0, -1);
381         }
382
383         $return = "$before<a href='$url' rel='external'>$display</a>$after";
384
385         /**
386          * Filters the comment author's returned URL link.
387          *
388          * @since 1.5.0
389          *
390          * @param string $return The HTML-formatted comment author URL link.
391          */
392         return apply_filters( 'get_comment_author_url_link', $return );
393 }
394
395 /**
396  * Displays the HTML link of the url of the author of the current comment.
397  *
398  * @since 0.71
399  * @since 4.6.0 Added the `$comment` parameter.
400  *
401  * @param string         $linktext Optional. Text to display instead of the comment author's
402  *                                 email address. Default empty.
403  * @param string         $before   Optional. Text or HTML to display before the email link.
404  *                                 Default empty.
405  * @param string         $after    Optional. Text or HTML to display after the email link.
406  *                                 Default empty.
407  * @param int|WP_Comment $comment  Optional. Comment ID or WP_Comment object.
408  *                                 Default is the current comment.
409  */
410 function comment_author_url_link( $linktext = '', $before = '', $after = '', $comment = 0 ) {
411         echo get_comment_author_url_link( $linktext, $before, $after, $comment );
412 }
413
414 /**
415  * Generates semantic classes for each comment element.
416  *
417  * @since 2.7.0
418  * @since 4.4.0 Added the ability for `$comment` to also accept a WP_Comment object.
419  *
420  * @param string|array   $class    Optional. One or more classes to add to the class list.
421  *                                 Default empty.
422  * @param int|WP_Comment $comment  Comment ID or WP_Comment object. Default current comment.
423  * @param int|WP_Post    $post_id  Post ID or WP_Post object. Default current post.
424  * @param bool           $echo     Optional. Whether to cho or return the output.
425  *                                 Default true.
426  * @return string If `$echo` is false, the class will be returned. Void otherwise.
427  */
428 function comment_class( $class = '', $comment = null, $post_id = null, $echo = true ) {
429         // Separates classes with a single space, collates classes for comment DIV
430         $class = 'class="' . join( ' ', get_comment_class( $class, $comment, $post_id ) ) . '"';
431         if ( $echo)
432                 echo $class;
433         else
434                 return $class;
435 }
436
437 /**
438  * Returns the classes for the comment div as an array.
439  *
440  * @since 2.7.0
441  * @since 4.4.0 Added the ability for `$comment_id` to also accept a WP_Comment object.
442  *
443  * @global int $comment_alt
444  * @global int $comment_depth
445  * @global int $comment_thread_alt
446  *
447  * @param string|array   $class      Optional. One or more classes to add to the class list. Default empty.
448  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object. Default current comment.
449  * @param int|WP_Post    $post_id    Post ID or WP_Post object. Default current post.
450  * @return array An array of classes.
451  */
452 function get_comment_class( $class = '', $comment_id = null, $post_id = null ) {
453         global $comment_alt, $comment_depth, $comment_thread_alt;
454
455         $classes = array();
456
457         $comment = get_comment( $comment_id );
458         if ( ! $comment ) {
459                 return $classes;
460         }
461
462         // Get the comment type (comment, trackback),
463         $classes[] = ( empty( $comment->comment_type ) ) ? 'comment' : $comment->comment_type;
464
465         // Add classes for comment authors that are registered users.
466         if ( $comment->user_id > 0 && $user = get_userdata( $comment->user_id ) ) {
467                 $classes[] = 'byuser';
468                 $classes[] = 'comment-author-' . sanitize_html_class( $user->user_nicename, $comment->user_id );
469                 // For comment authors who are the author of the post
470                 if ( $post = get_post($post_id) ) {
471                         if ( $comment->user_id === $post->post_author ) {
472                                 $classes[] = 'bypostauthor';
473                         }
474                 }
475         }
476
477         if ( empty($comment_alt) )
478                 $comment_alt = 0;
479         if ( empty($comment_depth) )
480                 $comment_depth = 1;
481         if ( empty($comment_thread_alt) )
482                 $comment_thread_alt = 0;
483
484         if ( $comment_alt % 2 ) {
485                 $classes[] = 'odd';
486                 $classes[] = 'alt';
487         } else {
488                 $classes[] = 'even';
489         }
490
491         $comment_alt++;
492
493         // Alt for top-level comments
494         if ( 1 == $comment_depth ) {
495                 if ( $comment_thread_alt % 2 ) {
496                         $classes[] = 'thread-odd';
497                         $classes[] = 'thread-alt';
498                 } else {
499                         $classes[] = 'thread-even';
500                 }
501                 $comment_thread_alt++;
502         }
503
504         $classes[] = "depth-$comment_depth";
505
506         if ( !empty($class) ) {
507                 if ( !is_array( $class ) )
508                         $class = preg_split('#\s+#', $class);
509                 $classes = array_merge($classes, $class);
510         }
511
512         $classes = array_map('esc_attr', $classes);
513
514         /**
515          * Filters the returned CSS classes for the current comment.
516          *
517          * @since 2.7.0
518          *
519          * @param array       $classes    An array of comment classes.
520          * @param string      $class      A comma-separated list of additional classes added to the list.
521          * @param int         $comment_id The comment id.
522          * @param WP_Comment  $comment    The comment object.
523          * @param int|WP_Post $post_id    The post ID or WP_Post object.
524          */
525         return apply_filters( 'comment_class', $classes, $class, $comment->comment_ID, $comment, $post_id );
526 }
527
528 /**
529  * Retrieve the comment date of the current comment.
530  *
531  * @since 1.5.0
532  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
533  *
534  * @param string          $d          Optional. The format of the date. Default user's setting.
535  * @param int|WP_Comment  $comment_ID WP_Comment or ID of the comment for which to get the date.
536  *                                    Default current comment.
537  * @return string The comment's date.
538  */
539 function get_comment_date( $d = '', $comment_ID = 0 ) {
540         $comment = get_comment( $comment_ID );
541         if ( '' == $d )
542                 $date = mysql2date(get_option('date_format'), $comment->comment_date);
543         else
544                 $date = mysql2date($d, $comment->comment_date);
545         /**
546          * Filters the returned comment date.
547          *
548          * @since 1.5.0
549          *
550          * @param string|int $date    Formatted date string or Unix timestamp.
551          * @param string     $d       The format of the date.
552          * @param WP_Comment $comment The comment object.
553          */
554         return apply_filters( 'get_comment_date', $date, $d, $comment );
555 }
556
557 /**
558  * Display the comment date of the current comment.
559  *
560  * @since 0.71
561  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
562  *
563  * @param string         $d          Optional. The format of the date. Default user's settings.
564  * @param int|WP_Comment $comment_ID WP_Comment or ID of the comment for which to print the date.
565  *                                   Default current comment.
566  */
567 function comment_date( $d = '', $comment_ID = 0 ) {
568         echo get_comment_date( $d, $comment_ID );
569 }
570
571 /**
572  * Retrieve the excerpt of the current comment.
573  *
574  * Will cut each word and only output the first 20 words with '&hellip;' at the end.
575  * If the word count is less than 20, then no truncating is done and no '&hellip;'
576  * will appear.
577  *
578  * @since 1.5.0
579  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
580  *
581  * @param int|WP_Comment $comment_ID  WP_Comment or ID of the comment for which to get the excerpt.
582  *                                    Default current comment.
583  * @return string The maybe truncated comment with 20 words or less.
584  */
585 function get_comment_excerpt( $comment_ID = 0 ) {
586         $comment = get_comment( $comment_ID );
587         $comment_text = strip_tags( str_replace( array( "\n", "\r" ), ' ', $comment->comment_content ) );
588         $words = explode( ' ', $comment_text );
589
590         /**
591          * Filters the amount of words used in the comment excerpt.
592          *
593          * @since 4.4.0
594          *
595          * @param int $comment_excerpt_length The amount of words you want to display in the comment excerpt.
596          */
597         $comment_excerpt_length = apply_filters( 'comment_excerpt_length', 20 );
598
599         $use_ellipsis = count( $words ) > $comment_excerpt_length;
600         if ( $use_ellipsis ) {
601                 $words = array_slice( $words, 0, $comment_excerpt_length );
602         }
603
604         $excerpt = trim( join( ' ', $words ) );
605         if ( $use_ellipsis ) {
606                 $excerpt .= '&hellip;';
607         }
608         /**
609          * Filters the retrieved comment excerpt.
610          *
611          * @since 1.5.0
612          * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added.
613          *
614          * @param string     $excerpt    The comment excerpt text.
615          * @param int        $comment_ID The comment ID.
616          * @param WP_Comment $comment    The comment object.
617          */
618         return apply_filters( 'get_comment_excerpt', $excerpt, $comment->comment_ID, $comment );
619 }
620
621 /**
622  * Display the excerpt of the current comment.
623  *
624  * @since 1.2.0
625  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
626  *
627  * @param int|WP_Comment $comment_ID  WP_Comment or ID of the comment for which to print the excerpt.
628  *                                    Default current comment.
629  */
630 function comment_excerpt( $comment_ID = 0 ) {
631         $comment         = get_comment( $comment_ID );
632         $comment_excerpt = get_comment_excerpt( $comment );
633
634         /**
635          * Filters the comment excerpt for display.
636          *
637          * @since 1.2.0
638          * @since 4.1.0 The `$comment_ID` parameter was added.
639          *
640          * @param string $comment_excerpt The comment excerpt text.
641          * @param int    $comment_ID      The comment ID.
642          */
643         echo apply_filters( 'comment_excerpt', $comment_excerpt, $comment->comment_ID );
644 }
645
646 /**
647  * Retrieve the comment id of the current comment.
648  *
649  * @since 1.5.0
650  *
651  * @return int The comment ID.
652  */
653 function get_comment_ID() {
654         $comment = get_comment();
655
656         /**
657          * Filters the returned comment ID.
658          *
659          * @since 1.5.0
660          * @since 4.1.0 The `$comment_ID` parameter was added.
661          *
662          * @param int        $comment_ID The current comment ID.
663          * @param WP_Comment $comment    The comment object.
664          */
665         return apply_filters( 'get_comment_ID', $comment->comment_ID, $comment );
666 }
667
668 /**
669  * Display the comment id of the current comment.
670  *
671  * @since 0.71
672  */
673 function comment_ID() {
674         echo get_comment_ID();
675 }
676
677 /**
678  * Retrieve the link to a given comment.
679  *
680  * @since 1.5.0
681  * @since 4.4.0 Added the ability for `$comment` to also accept a WP_Comment object. Added `$cpage` argument.
682  *
683  * @see get_page_of_comment()
684  *
685  * @global WP_Rewrite $wp_rewrite
686  * @global bool       $in_comment_loop
687  *
688  * @param WP_Comment|int|null $comment Comment to retrieve. Default current comment.
689  * @param array               $args {
690  *     An array of optional arguments to override the defaults.
691  *
692  *     @type string     $type      Passed to get_page_of_comment().
693  *     @type int        $page      Current page of comments, for calculating comment pagination.
694  *     @type int        $per_page  Per-page value for comment pagination.
695  *     @type int        $max_depth Passed to get_page_of_comment().
696  *     @type int|string $cpage     Value to use for the comment's "comment-page" or "cpage" value.
697  *                                 If provided, this value overrides any value calculated from `$page`
698  *                                 and `$per_page`.
699  * }
700  * @return string The permalink to the given comment.
701  */
702 function get_comment_link( $comment = null, $args = array() ) {
703         global $wp_rewrite, $in_comment_loop;
704
705         $comment = get_comment($comment);
706
707         // Back-compat.
708         if ( ! is_array( $args ) ) {
709                 $args = array( 'page' => $args );
710         }
711
712         $defaults = array(
713                 'type'      => 'all',
714                 'page'      => '',
715                 'per_page'  => '',
716                 'max_depth' => '',
717                 'cpage'     => null,
718         );
719         $args = wp_parse_args( $args, $defaults );
720
721         $link = get_permalink( $comment->comment_post_ID );
722
723         // The 'cpage' param takes precedence.
724         if ( ! is_null( $args['cpage'] ) ) {
725                 $cpage = $args['cpage'];
726
727         // No 'cpage' is provided, so we calculate one.
728         } else {
729                 if ( '' === $args['per_page'] && get_option( 'page_comments' ) ) {
730                         $args['per_page'] = get_option('comments_per_page');
731                 }
732
733                 if ( empty( $args['per_page'] ) ) {
734                         $args['per_page'] = 0;
735                         $args['page'] = 0;
736                 }
737
738                 $cpage = $args['page'];
739
740                 if ( '' == $cpage ) {
741                         if ( ! empty( $in_comment_loop ) ) {
742                                 $cpage = get_query_var( 'cpage' );
743                         } else {
744                                 // Requires a database hit, so we only do it when we can't figure out from context.
745                                 $cpage = get_page_of_comment( $comment->comment_ID, $args );
746                         }
747                 }
748
749                 /*
750                  * If the default page displays the oldest comments, the permalinks for comments on the default page
751                  * do not need a 'cpage' query var.
752                  */
753                 if ( 'oldest' === get_option( 'default_comments_page' ) && 1 === $cpage ) {
754                         $cpage = '';
755                 }
756         }
757
758         if ( $cpage && get_option( 'page_comments' ) ) {
759                 if ( $wp_rewrite->using_permalinks() ) {
760                         if ( $cpage ) {
761                                 $link = trailingslashit( $link ) . $wp_rewrite->comments_pagination_base . '-' . $cpage;
762                         }
763
764                         $link = user_trailingslashit( $link, 'comment' );
765                 } elseif ( $cpage ) {
766                         $link = add_query_arg( 'cpage', $cpage, $link );
767                 }
768
769         }
770
771         if ( $wp_rewrite->using_permalinks() ) {
772                 $link = user_trailingslashit( $link, 'comment' );
773         }
774
775         $link = $link . '#comment-' . $comment->comment_ID;
776
777         /**
778          * Filters the returned single comment permalink.
779          *
780          * @since 2.8.0
781          * @since 4.4.0 Added the `$cpage` parameter.
782          *
783          * @see get_page_of_comment()
784          *
785          * @param string     $link    The comment permalink with '#comment-$id' appended.
786          * @param WP_Comment $comment The current comment object.
787          * @param array      $args    An array of arguments to override the defaults.
788          * @param int        $cpage   The calculated 'cpage' value.
789          */
790         return apply_filters( 'get_comment_link', $link, $comment, $args, $cpage );
791 }
792
793 /**
794  * Retrieves the link to the current post comments.
795  *
796  * @since 1.5.0
797  *
798  * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post.
799  * @return string The link to the comments.
800  */
801 function get_comments_link( $post_id = 0 ) {
802         $hash = get_comments_number( $post_id ) ? '#comments' : '#respond';
803         $comments_link = get_permalink( $post_id ) . $hash;
804
805         /**
806          * Filters the returned post comments permalink.
807          *
808          * @since 3.6.0
809          *
810          * @param string      $comments_link Post comments permalink with '#comments' appended.
811          * @param int|WP_Post $post_id       Post ID or WP_Post object.
812          */
813         return apply_filters( 'get_comments_link', $comments_link, $post_id );
814 }
815
816 /**
817  * Display the link to the current post comments.
818  *
819  * @since 0.71
820  *
821  * @param string $deprecated   Not Used.
822  * @param string $deprecated_2 Not Used.
823  */
824 function comments_link( $deprecated = '', $deprecated_2 = '' ) {
825         if ( !empty( $deprecated ) )
826                 _deprecated_argument( __FUNCTION__, '0.72' );
827         if ( !empty( $deprecated_2 ) )
828                 _deprecated_argument( __FUNCTION__, '1.3.0' );
829         echo esc_url( get_comments_link() );
830 }
831
832 /**
833  * Retrieve the amount of comments a post has.
834  *
835  * @since 1.5.0
836  *
837  * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post.
838  * @return int The number of comments a post has.
839  */
840 function get_comments_number( $post_id = 0 ) {
841         $post = get_post( $post_id );
842
843         if ( ! $post ) {
844                 $count = 0;
845         } else {
846                 $count = $post->comment_count;
847                 $post_id = $post->ID;
848         }
849
850         /**
851          * Filters the returned comment count for a post.
852          *
853          * @since 1.5.0
854          *
855          * @param int $count   Number of comments a post has.
856          * @param int $post_id Post ID.
857          */
858         return apply_filters( 'get_comments_number', $count, $post_id );
859 }
860
861 /**
862  * Display the language string for the number of comments the current post has.
863  *
864  * @since 0.71
865  *
866  * @param string $zero       Optional. Text for no comments. Default false.
867  * @param string $one        Optional. Text for one comment. Default false.
868  * @param string $more       Optional. Text for more than one comment. Default false.
869  * @param string $deprecated Not used.
870  */
871 function comments_number( $zero = false, $one = false, $more = false, $deprecated = '' ) {
872         if ( ! empty( $deprecated ) ) {
873                 _deprecated_argument( __FUNCTION__, '1.3.0' );
874         }
875         echo get_comments_number_text( $zero, $one, $more );
876 }
877
878 /**
879  * Display the language string for the number of comments the current post has.
880  *
881  * @since 4.0.0
882  *
883  * @param string $zero Optional. Text for no comments. Default false.
884  * @param string $one  Optional. Text for one comment. Default false.
885  * @param string $more Optional. Text for more than one comment. Default false.
886  */
887 function get_comments_number_text( $zero = false, $one = false, $more = false ) {
888         $number = get_comments_number();
889
890         if ( $number > 1 ) {
891                 if ( false === $more ) {
892                         /* translators: %s: number of comments */
893                         $output = sprintf( _n( '%s Comment', '%s Comments', $number ), number_format_i18n( $number ) );
894                 } else {
895                         // % Comments
896                         /* translators: If comment number in your language requires declension,
897                          * translate this to 'on'. Do not translate into your own language.
898                          */
899                         if ( 'on' === _x( 'off', 'Comment number declension: on or off' ) ) {
900                                 $text = preg_replace( '#<span class="screen-reader-text">.+?</span>#', '', $more );
901                                 $text = preg_replace( '/&.+?;/', '', $text ); // Kill entities
902                                 $text = trim( strip_tags( $text ), '% ' );
903
904                                 // Replace '% Comments' with a proper plural form
905                                 if ( $text && ! preg_match( '/[0-9]+/', $text ) && false !== strpos( $more, '%' ) ) {
906                                         /* translators: %s: number of comments */
907                                         $new_text = _n( '%s Comment', '%s Comments', $number );
908                                         $new_text = trim( sprintf( $new_text, '' ) );
909
910                                         $more = str_replace( $text, $new_text, $more );
911                                         if ( false === strpos( $more, '%' ) ) {
912                                                 $more = '% ' . $more;
913                                         }
914                                 }
915                         }
916
917                         $output = str_replace( '%', number_format_i18n( $number ), $more );
918                 }
919         } elseif ( $number == 0 ) {
920                 $output = ( false === $zero ) ? __( 'No Comments' ) : $zero;
921         } else { // must be one
922                 $output = ( false === $one ) ? __( '1 Comment' ) : $one;
923         }
924         /**
925          * Filters the comments count for display.
926          *
927          * @since 1.5.0
928          *
929          * @see _n()
930          *
931          * @param string $output A translatable string formatted based on whether the count
932          *                       is equal to 0, 1, or 1+.
933          * @param int    $number The number of post comments.
934          */
935         return apply_filters( 'comments_number', $output, $number );
936 }
937
938 /**
939  * Retrieve the text of the current comment.
940  *
941  * @since 1.5.0
942  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
943  *
944  * @see Walker_Comment::comment()
945  *
946  * @param int|WP_Comment  $comment_ID WP_Comment or ID of the comment for which to get the text.
947  *                                    Default current comment.
948  * @param array           $args       Optional. An array of arguments. Default empty.
949  * @return string The comment content.
950  */
951 function get_comment_text( $comment_ID = 0, $args = array() ) {
952         $comment = get_comment( $comment_ID );
953
954         /**
955          * Filters the text of a comment.
956          *
957          * @since 1.5.0
958          *
959          * @see Walker_Comment::comment()
960          *
961          * @param string     $comment_content Text of the comment.
962          * @param WP_Comment $comment         The comment object.
963          * @param array      $args            An array of arguments.
964          */
965         return apply_filters( 'get_comment_text', $comment->comment_content, $comment, $args );
966 }
967
968 /**
969  * Display the text of the current comment.
970  *
971  * @since 0.71
972  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
973  *
974  * @see Walker_Comment::comment()
975  *
976  * @param int|WP_Comment  $comment_ID WP_Comment or ID of the comment for which to print the text.
977  *                                    Default current comment.
978  * @param array           $args       Optional. An array of arguments. Default empty array. Default empty.
979  */
980 function comment_text( $comment_ID = 0, $args = array() ) {
981         $comment = get_comment( $comment_ID );
982
983         $comment_text = get_comment_text( $comment, $args );
984         /**
985          * Filters the text of a comment to be displayed.
986          *
987          * @since 1.2.0
988          *
989          * @see Walker_Comment::comment()
990          *
991          * @param string     $comment_text Text of the current comment.
992          * @param WP_Comment $comment      The comment object.
993          * @param array      $args         An array of arguments.
994          */
995         echo apply_filters( 'comment_text', $comment_text, $comment, $args );
996 }
997
998 /**
999  * Retrieve the comment time of the current comment.
1000  *
1001  * @since 1.5.0
1002  *
1003  * @param string $d         Optional. The format of the time. Default user's settings.
1004  * @param bool   $gmt       Optional. Whether to use the GMT date. Default false.
1005  * @param bool   $translate Optional. Whether to translate the time (for use in feeds).
1006  *                          Default true.
1007  * @return string The formatted time.
1008  */
1009 function get_comment_time( $d = '', $gmt = false, $translate = true ) {
1010         $comment = get_comment();
1011
1012         $comment_date = $gmt ? $comment->comment_date_gmt : $comment->comment_date;
1013         if ( '' == $d )
1014                 $date = mysql2date(get_option('time_format'), $comment_date, $translate);
1015         else
1016                 $date = mysql2date($d, $comment_date, $translate);
1017
1018         /**
1019          * Filters the returned comment time.
1020          *
1021          * @since 1.5.0
1022          *
1023          * @param string|int $date      The comment time, formatted as a date string or Unix timestamp.
1024          * @param string     $d         Date format.
1025          * @param bool       $gmt       Whether the GMT date is in use.
1026          * @param bool       $translate Whether the time is translated.
1027          * @param WP_Comment $comment   The comment object.
1028          */
1029         return apply_filters( 'get_comment_time', $date, $d, $gmt, $translate, $comment );
1030 }
1031
1032 /**
1033  * Display the comment time of the current comment.
1034  *
1035  * @since 0.71
1036  *
1037  * @param string $d Optional. The format of the time. Default user's settings.
1038  */
1039 function comment_time( $d = '' ) {
1040         echo get_comment_time($d);
1041 }
1042
1043 /**
1044  * Retrieve the comment type of the current comment.
1045  *
1046  * @since 1.5.0
1047  * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object.
1048  *
1049  * @param int|WP_Comment $comment_ID Optional. WP_Comment or ID of the comment for which to get the type.
1050  *                                   Default current comment.
1051  * @return string The comment type.
1052  */
1053 function get_comment_type( $comment_ID = 0 ) {
1054         $comment = get_comment( $comment_ID );
1055         if ( '' == $comment->comment_type )
1056                 $comment->comment_type = 'comment';
1057
1058         /**
1059          * Filters the returned comment type.
1060          *
1061          * @since 1.5.0
1062          * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added.
1063          *
1064          * @param string     $comment_type The type of comment, such as 'comment', 'pingback', or 'trackback'.
1065          * @param int        $comment_ID   The comment ID.
1066          * @param WP_Comment $comment      The comment object.
1067          */
1068         return apply_filters( 'get_comment_type', $comment->comment_type, $comment->comment_ID, $comment );
1069 }
1070
1071 /**
1072  * Display the comment type of the current comment.
1073  *
1074  * @since 0.71
1075  *
1076  * @param string $commenttxt   Optional. String to display for comment type. Default false.
1077  * @param string $trackbacktxt Optional. String to display for trackback type. Default false.
1078  * @param string $pingbacktxt  Optional. String to display for pingback type. Default false.
1079  */
1080 function comment_type( $commenttxt = false, $trackbacktxt = false, $pingbacktxt = false ) {
1081         if ( false === $commenttxt ) $commenttxt = _x( 'Comment', 'noun' );
1082         if ( false === $trackbacktxt ) $trackbacktxt = __( 'Trackback' );
1083         if ( false === $pingbacktxt ) $pingbacktxt = __( 'Pingback' );
1084         $type = get_comment_type();
1085         switch( $type ) {
1086                 case 'trackback' :
1087                         echo $trackbacktxt;
1088                         break;
1089                 case 'pingback' :
1090                         echo $pingbacktxt;
1091                         break;
1092                 default :
1093                         echo $commenttxt;
1094         }
1095 }
1096
1097 /**
1098  * Retrieve The current post's trackback URL.
1099  *
1100  * There is a check to see if permalink's have been enabled and if so, will
1101  * retrieve the pretty path. If permalinks weren't enabled, the ID of the
1102  * current post is used and appended to the correct page to go to.
1103  *
1104  * @since 1.5.0
1105  *
1106  * @return string The trackback URL after being filtered.
1107  */
1108 function get_trackback_url() {
1109         if ( '' != get_option('permalink_structure') )
1110                 $tb_url = trailingslashit(get_permalink()) . user_trailingslashit('trackback', 'single_trackback');
1111         else
1112                 $tb_url = get_option('siteurl') . '/wp-trackback.php?p=' . get_the_ID();
1113
1114         /**
1115          * Filters the returned trackback URL.
1116          *
1117          * @since 2.2.0
1118          *
1119          * @param string $tb_url The trackback URL.
1120          */
1121         return apply_filters( 'trackback_url', $tb_url );
1122 }
1123
1124 /**
1125  * Display the current post's trackback URL.
1126  *
1127  * @since 0.71
1128  *
1129  * @param bool $deprecated_echo Not used.
1130  * @return void|string Should only be used to echo the trackback URL, use get_trackback_url()
1131  *                     for the result instead.
1132  */
1133 function trackback_url( $deprecated_echo = true ) {
1134         if ( true !== $deprecated_echo ) {
1135                 _deprecated_argument( __FUNCTION__, '2.5.0',
1136                         /* translators: %s: get_trackback_url() */
1137                         sprintf( __( 'Use %s instead if you do not want the value echoed.' ),
1138                                 '<code>get_trackback_url()</code>'
1139                         )
1140                 );
1141         }
1142
1143         if ( $deprecated_echo ) {
1144                 echo get_trackback_url();
1145         } else {
1146                 return get_trackback_url();
1147         }
1148 }
1149
1150 /**
1151  * Generate and display the RDF for the trackback information of current post.
1152  *
1153  * Deprecated in 3.0.0, and restored in 3.0.1.
1154  *
1155  * @since 0.71
1156  *
1157  * @param int $deprecated Not used (Was $timezone = 0).
1158  */
1159 function trackback_rdf( $deprecated = '' ) {
1160         if ( ! empty( $deprecated ) ) {
1161                 _deprecated_argument( __FUNCTION__, '2.5.0' );
1162         }
1163
1164         if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && false !== stripos( $_SERVER['HTTP_USER_AGENT'], 'W3C_Validator' ) ) {
1165                 return;
1166         }
1167
1168         echo '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
1169                         xmlns:dc="http://purl.org/dc/elements/1.1/"
1170                         xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
1171                 <rdf:Description rdf:about="';
1172         the_permalink();
1173         echo '"'."\n";
1174         echo '    dc:identifier="';
1175         the_permalink();
1176         echo '"'."\n";
1177         echo '    dc:title="'.str_replace('--', '&#x2d;&#x2d;', wptexturize(strip_tags(get_the_title()))).'"'."\n";
1178         echo '    trackback:ping="'.get_trackback_url().'"'." />\n";
1179         echo '</rdf:RDF>';
1180 }
1181
1182 /**
1183  * Whether the current post is open for comments.
1184  *
1185  * @since 1.5.0
1186  *
1187  * @param int|WP_Post $post_id Post ID or WP_Post object. Default current post.
1188  * @return bool True if the comments are open.
1189  */
1190 function comments_open( $post_id = null ) {
1191
1192         $_post = get_post($post_id);
1193
1194         $open = ( 'open' == $_post->comment_status );
1195
1196         /**
1197          * Filters whether the current post is open for comments.
1198          *
1199          * @since 2.5.0
1200          *
1201          * @param bool        $open    Whether the current post is open for comments.
1202          * @param int|WP_Post $post_id The post ID or WP_Post object.
1203          */
1204         return apply_filters( 'comments_open', $open, $post_id );
1205 }
1206
1207 /**
1208  * Whether the current post is open for pings.
1209  *
1210  * @since 1.5.0
1211  *
1212  * @param int|WP_Post $post_id Post ID or WP_Post object. Default current post.
1213  * @return bool True if pings are accepted
1214  */
1215 function pings_open( $post_id = null ) {
1216
1217         $_post = get_post($post_id);
1218
1219         $open = ( 'open' == $_post->ping_status );
1220
1221         /**
1222          * Filters whether the current post is open for pings.
1223          *
1224          * @since 2.5.0
1225          *
1226          * @param bool        $open    Whether the current post is open for pings.
1227          * @param int|WP_Post $post_id The post ID or WP_Post object.
1228          */
1229         return apply_filters( 'pings_open', $open, $post_id );
1230 }
1231
1232 /**
1233  * Display form token for unfiltered comments.
1234  *
1235  * Will only display nonce token if the current user has permissions for
1236  * unfiltered html. Won't display the token for other users.
1237  *
1238  * The function was backported to 2.0.10 and was added to versions 2.1.3 and
1239  * above. Does not exist in versions prior to 2.0.10 in the 2.0 branch and in
1240  * the 2.1 branch, prior to 2.1.3. Technically added in 2.2.0.
1241  *
1242  * Backported to 2.0.10.
1243  *
1244  * @since 2.1.3
1245  */
1246 function wp_comment_form_unfiltered_html_nonce() {
1247         $post = get_post();
1248         $post_id = $post ? $post->ID : 0;
1249
1250         if ( current_user_can( 'unfiltered_html' ) ) {
1251                 wp_nonce_field( 'unfiltered-html-comment_' . $post_id, '_wp_unfiltered_html_comment_disabled', false );
1252                 echo "<script>(function(){if(window===window.parent){document.getElementById('_wp_unfiltered_html_comment_disabled').name='_wp_unfiltered_html_comment';}})();</script>\n";
1253         }
1254 }
1255
1256 /**
1257  * Load the comment template specified in $file.
1258  *
1259  * Will not display the comments template if not on single post or page, or if
1260  * the post does not have comments.
1261  *
1262  * Uses the WordPress database object to query for the comments. The comments
1263  * are passed through the {@see 'comments_array'} filter hook with the list of comments
1264  * and the post ID respectively.
1265  *
1266  * The `$file` path is passed through a filter hook called {@see 'comments_template'},
1267  * which includes the TEMPLATEPATH and $file combined. Tries the $filtered path
1268  * first and if it fails it will require the default comment template from the
1269  * default theme. If either does not exist, then the WordPress process will be
1270  * halted. It is advised for that reason, that the default theme is not deleted.
1271  *
1272  * Will not try to get the comments if the post has none.
1273  *
1274  * @since 1.5.0
1275  *
1276  * @global WP_Query   $wp_query
1277  * @global WP_Post    $post
1278  * @global wpdb       $wpdb
1279  * @global int        $id
1280  * @global WP_Comment $comment
1281  * @global string     $user_login
1282  * @global int        $user_ID
1283  * @global string     $user_identity
1284  * @global bool       $overridden_cpage
1285  * @global bool       $withcomments
1286  *
1287  * @param string $file              Optional. The file to load. Default '/comments.php'.
1288  * @param bool   $separate_comments Optional. Whether to separate the comments by comment type.
1289  *                                  Default false.
1290  */
1291 function comments_template( $file = '/comments.php', $separate_comments = false ) {
1292         global $wp_query, $withcomments, $post, $wpdb, $id, $comment, $user_login, $user_ID, $user_identity, $overridden_cpage;
1293
1294         if ( !(is_single() || is_page() || $withcomments) || empty($post) )
1295                 return;
1296
1297         if ( empty($file) )
1298                 $file = '/comments.php';
1299
1300         $req = get_option('require_name_email');
1301
1302         /*
1303          * Comment author information fetched from the comment cookies.
1304          */
1305         $commenter = wp_get_current_commenter();
1306
1307         /*
1308          * The name of the current comment author escaped for use in attributes.
1309          * Escaped by sanitize_comment_cookies().
1310          */
1311         $comment_author = $commenter['comment_author'];
1312
1313         /*
1314          * The email address of the current comment author escaped for use in attributes.
1315          * Escaped by sanitize_comment_cookies().
1316          */
1317         $comment_author_email = $commenter['comment_author_email'];
1318
1319         /*
1320          * The url of the current comment author escaped for use in attributes.
1321          */
1322         $comment_author_url = esc_url($commenter['comment_author_url']);
1323
1324         $comment_args = array(
1325                 'orderby' => 'comment_date_gmt',
1326                 'order' => 'ASC',
1327                 'status'  => 'approve',
1328                 'post_id' => $post->ID,
1329                 'no_found_rows' => false,
1330                 'update_comment_meta_cache' => false, // We lazy-load comment meta for performance.
1331         );
1332
1333         if ( get_option('thread_comments') ) {
1334                 $comment_args['hierarchical'] = 'threaded';
1335         } else {
1336                 $comment_args['hierarchical'] = false;
1337         }
1338
1339         if ( $user_ID ) {
1340                 $comment_args['include_unapproved'] = array( $user_ID );
1341         } elseif ( ! empty( $comment_author_email ) ) {
1342                 $comment_args['include_unapproved'] = array( $comment_author_email );
1343         }
1344
1345         $per_page = 0;
1346         if ( get_option( 'page_comments' ) ) {
1347                 $per_page = (int) get_query_var( 'comments_per_page' );
1348                 if ( 0 === $per_page ) {
1349                         $per_page = (int) get_option( 'comments_per_page' );
1350                 }
1351
1352                 $comment_args['number'] = $per_page;
1353                 $page = (int) get_query_var( 'cpage' );
1354
1355                 if ( $page ) {
1356                         $comment_args['offset'] = ( $page - 1 ) * $per_page;
1357                 } elseif ( 'oldest' === get_option( 'default_comments_page' ) ) {
1358                         $comment_args['offset'] = 0;
1359                 } else {
1360                         // If fetching the first page of 'newest', we need a top-level comment count.
1361                         $top_level_query = new WP_Comment_Query();
1362                         $top_level_args  = array(
1363                                 'count'   => true,
1364                                 'orderby' => false,
1365                                 'post_id' => $post->ID,
1366                                 'status'  => 'approve',
1367                         );
1368
1369                         if ( $comment_args['hierarchical'] ) {
1370                                 $top_level_args['parent'] = 0;
1371                         }
1372
1373                         if ( isset( $comment_args['include_unapproved'] ) ) {
1374                                 $top_level_args['include_unapproved'] = $comment_args['include_unapproved'];
1375                         }
1376
1377                         $top_level_count = $top_level_query->query( $top_level_args );
1378
1379                         $comment_args['offset'] = ( ceil( $top_level_count / $per_page ) - 1 ) * $per_page;
1380                 }
1381         }
1382
1383         /**
1384          * Filters the arguments used to query comments in comments_template().
1385          *
1386          * @since 4.5.0
1387          *
1388          * @see WP_Comment_Query::__construct()
1389          *
1390          * @param array $comment_args {
1391          *     Array of WP_Comment_Query arguments.
1392          *
1393          *     @type string|array $orderby                   Field(s) to order by.
1394          *     @type string       $order                     Order of results. Accepts 'ASC' or 'DESC'.
1395          *     @type string       $status                    Comment status.
1396          *     @type array        $include_unapproved        Array of IDs or email addresses whose unapproved comments
1397          *                                                   will be included in results.
1398          *     @type int          $post_id                   ID of the post.
1399          *     @type bool         $no_found_rows             Whether to refrain from querying for found rows.
1400          *     @type bool         $update_comment_meta_cache Whether to prime cache for comment meta.
1401          *     @type bool|string  $hierarchical              Whether to query for comments hierarchically.
1402          *     @type int          $offset                    Comment offset.
1403          *     @type int          $number                    Number of comments to fetch.
1404          * }
1405          */
1406         $comment_args = apply_filters( 'comments_template_query_args', $comment_args );
1407         $comment_query = new WP_Comment_Query( $comment_args );
1408         $_comments = $comment_query->comments;
1409
1410         // Trees must be flattened before they're passed to the walker.
1411         if ( $comment_args['hierarchical'] ) {
1412                 $comments_flat = array();
1413                 foreach ( $_comments as $_comment ) {
1414                         $comments_flat[]  = $_comment;
1415                         $comment_children = $_comment->get_children( array(
1416                                 'format' => 'flat',
1417                                 'status' => $comment_args['status'],
1418                                 'orderby' => $comment_args['orderby']
1419                         ) );
1420
1421                         foreach ( $comment_children as $comment_child ) {
1422                                 $comments_flat[] = $comment_child;
1423                         }
1424                 }
1425         } else {
1426                 $comments_flat = $_comments;
1427         }
1428
1429         /**
1430          * Filters the comments array.
1431          *
1432          * @since 2.1.0
1433          *
1434          * @param array $comments Array of comments supplied to the comments template.
1435          * @param int   $post_ID  Post ID.
1436          */
1437         $wp_query->comments = apply_filters( 'comments_array', $comments_flat, $post->ID );
1438
1439         $comments = &$wp_query->comments;
1440         $wp_query->comment_count = count($wp_query->comments);
1441         $wp_query->max_num_comment_pages = $comment_query->max_num_pages;
1442
1443         if ( $separate_comments ) {
1444                 $wp_query->comments_by_type = separate_comments($comments);
1445                 $comments_by_type = &$wp_query->comments_by_type;
1446         } else {
1447                 $wp_query->comments_by_type = array();
1448         }
1449
1450         $overridden_cpage = false;
1451         if ( '' == get_query_var( 'cpage' ) && $wp_query->max_num_comment_pages > 1 ) {
1452                 set_query_var( 'cpage', 'newest' == get_option('default_comments_page') ? get_comment_pages_count() : 1 );
1453                 $overridden_cpage = true;
1454         }
1455
1456         if ( !defined('COMMENTS_TEMPLATE') )
1457                 define('COMMENTS_TEMPLATE', true);
1458
1459         $theme_template = STYLESHEETPATH . $file;
1460         /**
1461          * Filters the path to the theme template file used for the comments template.
1462          *
1463          * @since 1.5.1
1464          *
1465          * @param string $theme_template The path to the theme template file.
1466          */
1467         $include = apply_filters( 'comments_template', $theme_template );
1468         if ( file_exists( $include ) )
1469                 require( $include );
1470         elseif ( file_exists( TEMPLATEPATH . $file ) )
1471                 require( TEMPLATEPATH . $file );
1472         else // Backward compat code will be removed in a future release
1473                 require( ABSPATH . WPINC . '/theme-compat/comments.php');
1474 }
1475
1476 /**
1477  * Displays the link to the comments for the current post ID.
1478  *
1479  * @since 0.71
1480  *
1481  * @param string $zero      Optional. String to display when no comments. Default false.
1482  * @param string $one       Optional. String to display when only one comment is available.
1483  *                          Default false.
1484  * @param string $more      Optional. String to display when there are more than one comment.
1485  *                          Default false.
1486  * @param string $css_class Optional. CSS class to use for comments. Default empty.
1487  * @param string $none      Optional. String to display when comments have been turned off.
1488  *                          Default false.
1489  */
1490 function comments_popup_link( $zero = false, $one = false, $more = false, $css_class = '', $none = false ) {
1491         $id = get_the_ID();
1492         $title = get_the_title();
1493         $number = get_comments_number( $id );
1494
1495         if ( false === $zero ) {
1496                 /* translators: %s: post title */
1497                 $zero = sprintf( __( 'No Comments<span class="screen-reader-text"> on %s</span>' ), $title );
1498         }
1499
1500         if ( false === $one ) {
1501                 /* translators: %s: post title */
1502                 $one = sprintf( __( '1 Comment<span class="screen-reader-text"> on %s</span>' ), $title );
1503         }
1504
1505         if ( false === $more ) {
1506                 /* translators: 1: Number of comments 2: post title */
1507                 $more = _n( '%1$s Comment<span class="screen-reader-text"> on %2$s</span>', '%1$s Comments<span class="screen-reader-text"> on %2$s</span>', $number );
1508                 $more = sprintf( $more, number_format_i18n( $number ), $title );
1509         }
1510
1511         if ( false === $none ) {
1512                 /* translators: %s: post title */
1513                 $none = sprintf( __( 'Comments Off<span class="screen-reader-text"> on %s</span>' ), $title );
1514         }
1515
1516         if ( 0 == $number && !comments_open() && !pings_open() ) {
1517                 echo '<span' . ((!empty($css_class)) ? ' class="' . esc_attr( $css_class ) . '"' : '') . '>' . $none . '</span>';
1518                 return;
1519         }
1520
1521         if ( post_password_required() ) {
1522                 _e( 'Enter your password to view comments.' );
1523                 return;
1524         }
1525
1526         echo '<a href="';
1527         if ( 0 == $number ) {
1528                 $respond_link = get_permalink() . '#respond';
1529                 /**
1530                  * Filters the respond link when a post has no comments.
1531                  *
1532                  * @since 4.4.0
1533                  *
1534                  * @param string $respond_link The default response link.
1535                  * @param integer $id The post ID.
1536                  */
1537                 echo apply_filters( 'respond_link', $respond_link, $id );
1538         } else {
1539                 comments_link();
1540         }
1541         echo '"';
1542
1543         if ( !empty( $css_class ) ) {
1544                 echo ' class="'.$css_class.'" ';
1545         }
1546
1547         $attributes = '';
1548         /**
1549          * Filters the comments link attributes for display.
1550          *
1551          * @since 2.5.0
1552          *
1553          * @param string $attributes The comments link attributes. Default empty.
1554          */
1555         echo apply_filters( 'comments_popup_link_attributes', $attributes );
1556
1557         echo '>';
1558         comments_number( $zero, $one, $more );
1559         echo '</a>';
1560 }
1561
1562 /**
1563  * Retrieve HTML content for reply to comment link.
1564  *
1565  * @since 2.7.0
1566  * @since 4.4.0 Added the ability for `$comment` to also accept a WP_Comment object.
1567  *
1568  * @param array $args {
1569  *     Optional. Override default arguments.
1570  *
1571  *     @type string $add_below  The first part of the selector used to identify the comment to respond below.
1572  *                              The resulting value is passed as the first parameter to addComment.moveForm(),
1573  *                              concatenated as $add_below-$comment->comment_ID. Default 'comment'.
1574  *     @type string $respond_id The selector identifying the responding comment. Passed as the third parameter
1575  *                              to addComment.moveForm(), and appended to the link URL as a hash value.
1576  *                              Default 'respond'.
1577  *     @type string $reply_text The text of the Reply link. Default 'Reply'.
1578  *     @type string $login_text The text of the link to reply if logged out. Default 'Log in to Reply'.
1579  *     @type int    $depth'     The depth of the new comment. Must be greater than 0 and less than the value
1580  *                              of the 'thread_comments_depth' option set in Settings > Discussion. Default 0.
1581  *     @type string $before     The text or HTML to add before the reply link. Default empty.
1582  *     @type string $after      The text or HTML to add after the reply link. Default empty.
1583  * }
1584  * @param int|WP_Comment $comment Comment being replied to. Default current comment.
1585  * @param int|WP_Post    $post    Post ID or WP_Post object the comment is going to be displayed on.
1586  *                                Default current post.
1587  * @return void|false|string Link to show comment form, if successful. False, if comments are closed.
1588  */
1589 function get_comment_reply_link( $args = array(), $comment = null, $post = null ) {
1590         $defaults = array(
1591                 'add_below'     => 'comment',
1592                 'respond_id'    => 'respond',
1593                 'reply_text'    => __( 'Reply' ),
1594                 'reply_to_text' => __( 'Reply to %s' ),
1595                 'login_text'    => __( 'Log in to Reply' ),
1596                 'depth'         => 0,
1597                 'before'        => '',
1598                 'after'         => ''
1599         );
1600
1601         $args = wp_parse_args( $args, $defaults );
1602
1603         if ( 0 == $args['depth'] || $args['max_depth'] <= $args['depth'] ) {
1604                 return;
1605         }
1606
1607         $comment = get_comment( $comment );
1608
1609         if ( empty( $post ) ) {
1610                 $post = $comment->comment_post_ID;
1611         }
1612
1613         $post = get_post( $post );
1614
1615         if ( ! comments_open( $post->ID ) ) {
1616                 return false;
1617         }
1618
1619         /**
1620          * Filters the comment reply link arguments.
1621          *
1622          * @since 4.1.0
1623          *
1624          * @param array      $args    Comment reply link arguments. See get_comment_reply_link()
1625          *                            for more information on accepted arguments.
1626          * @param WP_Comment $comment The object of the comment being replied to.
1627          * @param WP_Post    $post    The WP_Post object.
1628          */
1629         $args = apply_filters( 'comment_reply_link_args', $args, $comment, $post );
1630
1631         if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) {
1632                 $link = sprintf( '<a rel="nofollow" class="comment-reply-login" href="%s">%s</a>',
1633                         esc_url( wp_login_url( get_permalink() ) ),
1634                         $args['login_text']
1635                 );
1636         } else {
1637                 $onclick = sprintf( 'return addComment.moveForm( "%1$s-%2$s", "%2$s", "%3$s", "%4$s" )',
1638                         $args['add_below'], $comment->comment_ID, $args['respond_id'], $post->ID
1639                 );
1640
1641                 $link = sprintf( "<a rel='nofollow' class='comment-reply-link' href='%s' onclick='%s' aria-label='%s'>%s</a>",
1642                         esc_url( add_query_arg( 'replytocom', $comment->comment_ID, get_permalink( $post->ID ) ) ) . "#" . $args['respond_id'],
1643                         $onclick,
1644                         esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ),
1645                         $args['reply_text']
1646                 );
1647         }
1648
1649         /**
1650          * Filters the comment reply link.
1651          *
1652          * @since 2.7.0
1653          *
1654          * @param string  $link    The HTML markup for the comment reply link.
1655          * @param array   $args    An array of arguments overriding the defaults.
1656          * @param object  $comment The object of the comment being replied.
1657          * @param WP_Post $post    The WP_Post object.
1658          */
1659         return apply_filters( 'comment_reply_link', $args['before'] . $link . $args['after'], $args, $comment, $post );
1660 }
1661
1662 /**
1663  * Displays the HTML content for reply to comment link.
1664  *
1665  * @since 2.7.0
1666  *
1667  * @see get_comment_reply_link()
1668  *
1669  * @param array       $args    Optional. Override default options.
1670  * @param int         $comment Comment being replied to. Default current comment.
1671  * @param int|WP_Post $post    Post ID or WP_Post object the comment is going to be displayed on.
1672  *                             Default current post.
1673  * @return mixed Link to show comment form, if successful. False, if comments are closed.
1674  */
1675 function comment_reply_link($args = array(), $comment = null, $post = null) {
1676         echo get_comment_reply_link($args, $comment, $post);
1677 }
1678
1679 /**
1680  * Retrieve HTML content for reply to post link.
1681  *
1682  * @since 2.7.0
1683  *
1684  * @param array $args {
1685  *     Optional. Override default arguments.
1686  *
1687  *     @type string $add_below  The first part of the selector used to identify the comment to respond below.
1688  *                              The resulting value is passed as the first parameter to addComment.moveForm(),
1689  *                              concatenated as $add_below-$comment->comment_ID. Default is 'post'.
1690  *     @type string $respond_id The selector identifying the responding comment. Passed as the third parameter
1691  *                              to addComment.moveForm(), and appended to the link URL as a hash value.
1692  *                              Default 'respond'.
1693  *     @type string $reply_text Text of the Reply link. Default is 'Leave a Comment'.
1694  *     @type string $login_text Text of the link to reply if logged out. Default is 'Log in to leave a Comment'.
1695  *     @type string $before     Text or HTML to add before the reply link. Default empty.
1696  *     @type string $after      Text or HTML to add after the reply link. Default empty.
1697  * }
1698  * @param int|WP_Post $post    Optional. Post ID or WP_Post object the comment is going to be displayed on.
1699  *                             Default current post.
1700  * @return false|null|string Link to show comment form, if successful. False, if comments are closed.
1701  */
1702 function get_post_reply_link($args = array(), $post = null) {
1703         $defaults = array(
1704                 'add_below'  => 'post',
1705                 'respond_id' => 'respond',
1706                 'reply_text' => __('Leave a Comment'),
1707                 'login_text' => __('Log in to leave a Comment'),
1708                 'before'     => '',
1709                 'after'      => '',
1710         );
1711
1712         $args = wp_parse_args($args, $defaults);
1713
1714         $post = get_post($post);
1715
1716         if ( ! comments_open( $post->ID ) ) {
1717                 return false;
1718         }
1719
1720         if ( get_option('comment_registration') && ! is_user_logged_in() ) {
1721                 $link = sprintf( '<a rel="nofollow" class="comment-reply-login" href="%s">%s</a>',
1722                         wp_login_url( get_permalink() ),
1723                         $args['login_text']
1724                 );
1725         } else {
1726                 $onclick = sprintf( 'return addComment.moveForm( "%1$s-%2$s", "0", "%3$s", "%2$s" )',
1727                         $args['add_below'], $post->ID, $args['respond_id']
1728                 );
1729
1730                 $link = sprintf( "<a rel='nofollow' class='comment-reply-link' href='%s' onclick='%s'>%s</a>",
1731                         get_permalink( $post->ID ) . '#' . $args['respond_id'],
1732                         $onclick,
1733                         $args['reply_text']
1734                 );
1735         }
1736         $formatted_link = $args['before'] . $link . $args['after'];
1737
1738         /**
1739          * Filters the formatted post comments link HTML.
1740          *
1741          * @since 2.7.0
1742          *
1743          * @param string      $formatted The HTML-formatted post comments link.
1744          * @param int|WP_Post $post      The post ID or WP_Post object.
1745          */
1746         return apply_filters( 'post_comments_link', $formatted_link, $post );
1747 }
1748
1749 /**
1750  * Displays the HTML content for reply to post link.
1751  *
1752  * @since 2.7.0
1753  *
1754  * @see get_post_reply_link()
1755  *
1756  * @param array       $args Optional. Override default options,
1757  * @param int|WP_Post $post Post ID or WP_Post object the comment is going to be displayed on.
1758  *                          Default current post.
1759  * @return string|bool|null Link to show comment form, if successful. False, if comments are closed.
1760  */
1761 function post_reply_link($args = array(), $post = null) {
1762         echo get_post_reply_link($args, $post);
1763 }
1764
1765 /**
1766  * Retrieve HTML content for cancel comment reply link.
1767  *
1768  * @since 2.7.0
1769  *
1770  * @param string $text Optional. Text to display for cancel reply link. Default empty.
1771  * @return string
1772  */
1773 function get_cancel_comment_reply_link( $text = '' ) {
1774         if ( empty($text) )
1775                 $text = __('Click here to cancel reply.');
1776
1777         $style = isset($_GET['replytocom']) ? '' : ' style="display:none;"';
1778         $link = esc_html( remove_query_arg('replytocom') ) . '#respond';
1779
1780         $formatted_link = '<a rel="nofollow" id="cancel-comment-reply-link" href="' . $link . '"' . $style . '>' . $text . '</a>';
1781
1782         /**
1783          * Filters the cancel comment reply link HTML.
1784          *
1785          * @since 2.7.0
1786          *
1787          * @param string $formatted_link The HTML-formatted cancel comment reply link.
1788          * @param string $link           Cancel comment reply link URL.
1789          * @param string $text           Cancel comment reply link text.
1790          */
1791         return apply_filters( 'cancel_comment_reply_link', $formatted_link, $link, $text );
1792 }
1793
1794 /**
1795  * Display HTML content for cancel comment reply link.
1796  *
1797  * @since 2.7.0
1798  *
1799  * @param string $text Optional. Text to display for cancel reply link. Default empty.
1800  */
1801 function cancel_comment_reply_link( $text = '' ) {
1802         echo get_cancel_comment_reply_link($text);
1803 }
1804
1805 /**
1806  * Retrieve hidden input HTML for replying to comments.
1807  *
1808  * @since 3.0.0
1809  *
1810  * @param int $id Optional. Post ID. Default current post ID.
1811  * @return string Hidden input HTML for replying to comments
1812  */
1813 function get_comment_id_fields( $id = 0 ) {
1814         if ( empty( $id ) )
1815                 $id = get_the_ID();
1816
1817         $replytoid = isset($_GET['replytocom']) ? (int) $_GET['replytocom'] : 0;
1818         $result  = "<input type='hidden' name='comment_post_ID' value='$id' id='comment_post_ID' />\n";
1819         $result .= "<input type='hidden' name='comment_parent' id='comment_parent' value='$replytoid' />\n";
1820
1821         /**
1822          * Filters the returned comment id fields.
1823          *
1824          * @since 3.0.0
1825          *
1826          * @param string $result    The HTML-formatted hidden id field comment elements.
1827          * @param int    $id        The post ID.
1828          * @param int    $replytoid The id of the comment being replied to.
1829          */
1830         return apply_filters( 'comment_id_fields', $result, $id, $replytoid );
1831 }
1832
1833 /**
1834  * Output hidden input HTML for replying to comments.
1835  *
1836  * @since 2.7.0
1837  *
1838  * @param int $id Optional. Post ID. Default current post ID.
1839  */
1840 function comment_id_fields( $id = 0 ) {
1841         echo get_comment_id_fields( $id );
1842 }
1843
1844 /**
1845  * Display text based on comment reply status.
1846  *
1847  * Only affects users with JavaScript disabled.
1848  *
1849  * @internal The $comment global must be present to allow template tags access to the current
1850  *           comment. See https://core.trac.wordpress.org/changeset/36512.
1851  *
1852  * @since 2.7.0
1853  *
1854  * @global WP_Comment $comment Current comment.
1855  *
1856  * @param string $noreplytext  Optional. Text to display when not replying to a comment.
1857  *                             Default false.
1858  * @param string $replytext    Optional. Text to display when replying to a comment.
1859  *                             Default false. Accepts "%s" for the author of the comment
1860  *                             being replied to.
1861  * @param string $linktoparent Optional. Boolean to control making the author's name a link
1862  *                             to their comment. Default true.
1863  */
1864 function comment_form_title( $noreplytext = false, $replytext = false, $linktoparent = true ) {
1865         global $comment;
1866
1867         if ( false === $noreplytext ) $noreplytext = __( 'Leave a Reply' );
1868         if ( false === $replytext ) $replytext = __( 'Leave a Reply to %s' );
1869
1870         $replytoid = isset($_GET['replytocom']) ? (int) $_GET['replytocom'] : 0;
1871
1872         if ( 0 == $replytoid )
1873                 echo $noreplytext;
1874         else {
1875                 // Sets the global so that template tags can be used in the comment form.
1876                 $comment = get_comment($replytoid);
1877                 $author = ( $linktoparent ) ? '<a href="#comment-' . get_comment_ID() . '">' . get_comment_author( $comment ) . '</a>' : get_comment_author( $comment );
1878                 printf( $replytext, $author );
1879         }
1880 }
1881
1882 /**
1883  * List comments.
1884  *
1885  * Used in the comments.php template to list comments for a particular post.
1886  *
1887  * @since 2.7.0
1888  *
1889  * @see WP_Query->comments
1890  *
1891  * @global WP_Query $wp_query
1892  * @global int      $comment_alt
1893  * @global int      $comment_depth
1894  * @global int      $comment_thread_alt
1895  * @global bool     $overridden_cpage
1896  * @global bool     $in_comment_loop
1897  *
1898  * @param string|array $args {
1899  *     Optional. Formatting options.
1900  *
1901  *     @type object $walker            Instance of a Walker class to list comments. Default null.
1902  *     @type int    $max_depth         The maximum comments depth. Default empty.
1903  *     @type string $style             The style of list ordering. Default 'ul'. Accepts 'ul', 'ol'.
1904  *     @type string $callback          Callback function to use. Default null.
1905  *     @type string $end-callback      Callback function to use at the end. Default null.
1906  *     @type string $type              Type of comments to list.
1907  *                                     Default 'all'. Accepts 'all', 'comment', 'pingback', 'trackback', 'pings'.
1908  *     @type int    $page              Page ID to list comments for. Default empty.
1909  *     @type int    $per_page          Number of comments to list per page. Default empty.
1910  *     @type int    $avatar_size       Height and width dimensions of the avatar size. Default 32.
1911  *     @type string $reverse_top_level Ordering of the listed comments. Default null. Accepts 'desc', 'asc'.
1912  *     @type bool   $reverse_children  Whether to reverse child comments in the list. Default null.
1913  *     @type string $format            How to format the comments list.
1914  *                                     Default 'html5' if the theme supports it. Accepts 'html5', 'xhtml'.
1915  *     @type bool   $short_ping        Whether to output short pings. Default false.
1916  *     @type bool   $echo              Whether to echo the output or return it. Default true.
1917  * }
1918  * @param array $comments Optional. Array of WP_Comment objects.
1919  */
1920 function wp_list_comments( $args = array(), $comments = null ) {
1921         global $wp_query, $comment_alt, $comment_depth, $comment_thread_alt, $overridden_cpage, $in_comment_loop;
1922
1923         $in_comment_loop = true;
1924
1925         $comment_alt = $comment_thread_alt = 0;
1926         $comment_depth = 1;
1927
1928         $defaults = array(
1929                 'walker'            => null,
1930                 'max_depth'         => '',
1931                 'style'             => 'ul',
1932                 'callback'          => null,
1933                 'end-callback'      => null,
1934                 'type'              => 'all',
1935                 'page'              => '',
1936                 'per_page'          => '',
1937                 'avatar_size'       => 32,
1938                 'reverse_top_level' => null,
1939                 'reverse_children'  => '',
1940                 'format'            => current_theme_supports( 'html5', 'comment-list' ) ? 'html5' : 'xhtml',
1941                 'short_ping'        => false,
1942                 'echo'              => true,
1943         );
1944
1945         $r = wp_parse_args( $args, $defaults );
1946
1947         /**
1948          * Filters the arguments used in retrieving the comment list.
1949          *
1950          * @since 4.0.0
1951          *
1952          * @see wp_list_comments()
1953          *
1954          * @param array $r An array of arguments for displaying comments.
1955          */
1956         $r = apply_filters( 'wp_list_comments_args', $r );
1957
1958         // Figure out what comments we'll be looping through ($_comments)
1959         if ( null !== $comments ) {
1960                 $comments = (array) $comments;
1961                 if ( empty($comments) )
1962                         return;
1963                 if ( 'all' != $r['type'] ) {
1964                         $comments_by_type = separate_comments($comments);
1965                         if ( empty($comments_by_type[$r['type']]) )
1966                                 return;
1967                         $_comments = $comments_by_type[$r['type']];
1968                 } else {
1969                         $_comments = $comments;
1970                 }
1971         } else {
1972                 /*
1973                  * If 'page' or 'per_page' has been passed, and does not match what's in $wp_query,
1974                  * perform a separate comment query and allow Walker_Comment to paginate.
1975                  */
1976                 if ( $r['page'] || $r['per_page'] ) {
1977                         $current_cpage = get_query_var( 'cpage' );
1978                         if ( ! $current_cpage ) {
1979                                 $current_cpage = 'newest' === get_option( 'default_comments_page' ) ? 1 : $wp_query->max_num_comment_pages;
1980                         }
1981
1982                         $current_per_page = get_query_var( 'comments_per_page' );
1983                         if ( $r['page'] != $current_cpage || $r['per_page'] != $current_per_page ) {
1984                                 $comment_args = array(
1985                                         'post_id' => get_the_ID(),
1986                                         'orderby' => 'comment_date_gmt',
1987                                         'order' => 'ASC',
1988                                         'status' => 'approve',
1989                                 );
1990
1991                                 if ( is_user_logged_in() ) {
1992                                         $comment_args['include_unapproved'] = get_current_user_id();
1993                                 } else {
1994                                         $commenter = wp_get_current_commenter();
1995                                         if ( $commenter['comment_author_email'] ) {
1996                                                 $comment_args['include_unapproved'] = $commenter['comment_author_email'];
1997                                         }
1998                                 }
1999
2000                                 $comments = get_comments( $comment_args );
2001
2002                                 if ( 'all' != $r['type'] ) {
2003                                         $comments_by_type = separate_comments( $comments );
2004                                         if ( empty( $comments_by_type[ $r['type'] ] ) ) {
2005                                                 return;
2006                                         }
2007
2008                                         $_comments = $comments_by_type[ $r['type'] ];
2009                                 } else {
2010                                         $_comments = $comments;
2011                                 }
2012                         }
2013
2014                 // Otherwise, fall back on the comments from `$wp_query->comments`.
2015                 } else {
2016                         if ( empty($wp_query->comments) )
2017                                 return;
2018                         if ( 'all' != $r['type'] ) {
2019                                 if ( empty($wp_query->comments_by_type) )
2020                                         $wp_query->comments_by_type = separate_comments($wp_query->comments);
2021                                 if ( empty($wp_query->comments_by_type[$r['type']]) )
2022                                         return;
2023                                 $_comments = $wp_query->comments_by_type[$r['type']];
2024                         } else {
2025                                 $_comments = $wp_query->comments;
2026                         }
2027
2028                         if ( $wp_query->max_num_comment_pages ) {
2029                                 $default_comments_page = get_option( 'default_comments_page' );
2030                                 $cpage = get_query_var( 'cpage' );
2031                                 if ( 'newest' === $default_comments_page ) {
2032                                         $r['cpage'] = $cpage;
2033
2034                                 /*
2035                                  * When first page shows oldest comments, post permalink is the same as
2036                                  * the comment permalink.
2037                                  */
2038                                 } elseif ( $cpage == 1 ) {
2039                                         $r['cpage'] = '';
2040                                 } else {
2041                                         $r['cpage'] = $cpage;
2042                                 }
2043
2044                                 $r['page'] = 0;
2045                                 $r['per_page'] = 0;
2046                         }
2047                 }
2048         }
2049
2050         if ( '' === $r['per_page'] && get_option( 'page_comments' ) ) {
2051                 $r['per_page'] = get_query_var('comments_per_page');
2052         }
2053
2054         if ( empty($r['per_page']) ) {
2055                 $r['per_page'] = 0;
2056                 $r['page'] = 0;
2057         }
2058
2059         if ( '' === $r['max_depth'] ) {
2060                 if ( get_option('thread_comments') )
2061                         $r['max_depth'] = get_option('thread_comments_depth');
2062                 else
2063                         $r['max_depth'] = -1;
2064         }
2065
2066         if ( '' === $r['page'] ) {
2067                 if ( empty($overridden_cpage) ) {
2068                         $r['page'] = get_query_var('cpage');
2069                 } else {
2070                         $threaded = ( -1 != $r['max_depth'] );
2071                         $r['page'] = ( 'newest' == get_option('default_comments_page') ) ? get_comment_pages_count($_comments, $r['per_page'], $threaded) : 1;
2072                         set_query_var( 'cpage', $r['page'] );
2073                 }
2074         }
2075         // Validation check
2076         $r['page'] = intval($r['page']);
2077         if ( 0 == $r['page'] && 0 != $r['per_page'] )
2078                 $r['page'] = 1;
2079
2080         if ( null === $r['reverse_top_level'] )
2081                 $r['reverse_top_level'] = ( 'desc' == get_option('comment_order') );
2082
2083         wp_queue_comments_for_comment_meta_lazyload( $_comments );
2084
2085         if ( empty( $r['walker'] ) ) {
2086                 $walker = new Walker_Comment;
2087         } else {
2088                 $walker = $r['walker'];
2089         }
2090
2091         $output = $walker->paged_walk( $_comments, $r['max_depth'], $r['page'], $r['per_page'], $r );
2092
2093         $in_comment_loop = false;
2094
2095         if ( $r['echo'] ) {
2096                 echo $output;
2097         } else {
2098                 return $output;
2099         }
2100 }
2101
2102 /**
2103  * Outputs a complete commenting form for use within a template.
2104  *
2105  * Most strings and form fields may be controlled through the $args array passed
2106  * into the function, while you may also choose to use the {@see 'comment_form_default_fields'}
2107  * filter to modify the array of default fields if you'd just like to add a new
2108  * one or remove a single field. All fields are also individually passed through
2109  * a filter of the {@see 'comment_form_field_$name'} where $name is the key used
2110  * in the array of fields.
2111  *
2112  * @since 3.0.0
2113  * @since 4.1.0 Introduced the 'class_submit' argument.
2114  * @since 4.2.0 Introduced the 'submit_button' and 'submit_fields' arguments.
2115  * @since 4.4.0 Introduced the 'class_form', 'title_reply_before', 'title_reply_after',
2116  *              'cancel_reply_before', and 'cancel_reply_after' arguments.
2117  * @since 4.5.0 The 'author', 'email', and 'url' form fields are limited to 245, 100,
2118  *              and 200 characters, respectively.
2119  * @since 4.6.0 Introduced the 'action' argument.
2120  *
2121  * @param array       $args {
2122  *     Optional. Default arguments and form fields to override.
2123  *
2124  *     @type array $fields {
2125  *         Default comment fields, filterable by default via the {@see 'comment_form_default_fields'} hook.
2126  *
2127  *         @type string $author Comment author field HTML.
2128  *         @type string $email  Comment author email field HTML.
2129  *         @type string $url    Comment author URL field HTML.
2130  *     }
2131  *     @type string $comment_field        The comment textarea field HTML.
2132  *     @type string $must_log_in          HTML element for a 'must be logged in to comment' message.
2133  *     @type string $logged_in_as         HTML element for a 'logged in as [user]' message.
2134  *     @type string $comment_notes_before HTML element for a message displayed before the comment fields
2135  *                                        if the user is not logged in.
2136  *                                        Default 'Your email address will not be published.'.
2137  *     @type string $comment_notes_after  HTML element for a message displayed after the textarea field.
2138  *     @type string $action               The comment form element action attribute. Default '/wp-comments-post.php'.
2139  *     @type string $id_form              The comment form element id attribute. Default 'commentform'.
2140  *     @type string $id_submit            The comment submit element id attribute. Default 'submit'.
2141  *     @type string $class_form           The comment form element class attribute. Default 'comment-form'.
2142  *     @type string $class_submit         The comment submit element class attribute. Default 'submit'.
2143  *     @type string $name_submit          The comment submit element name attribute. Default 'submit'.
2144  *     @type string $title_reply          The translatable 'reply' button label. Default 'Leave a Reply'.
2145  *     @type string $title_reply_to       The translatable 'reply-to' button label. Default 'Leave a Reply to %s',
2146  *                                        where %s is the author of the comment being replied to.
2147  *     @type string $title_reply_before   HTML displayed before the comment form title.
2148  *                                        Default: '<h3 id="reply-title" class="comment-reply-title">'.
2149  *     @type string $title_reply_after    HTML displayed after the comment form title.
2150  *                                        Default: '</h3>'.
2151  *     @type string $cancel_reply_before  HTML displayed before the cancel reply link.
2152  *     @type string $cancel_reply_after   HTML displayed after the cancel reply link.
2153  *     @type string $cancel_reply_link    The translatable 'cancel reply' button label. Default 'Cancel reply'.
2154  *     @type string $label_submit         The translatable 'submit' button label. Default 'Post a comment'.
2155  *     @type string $submit_button        HTML format for the Submit button.
2156  *                                        Default: '<input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" />'.
2157  *     @type string $submit_field         HTML format for the markup surrounding the Submit button and comment hidden
2158  *                                        fields. Default: '<p class="form-submit">%1$s %2$s</a>', where %1$s is the
2159  *                                        submit button markup and %2$s is the comment hidden fields.
2160  *     @type string $format               The comment form format. Default 'xhtml'. Accepts 'xhtml', 'html5'.
2161  * }
2162  * @param int|WP_Post $post_id Post ID or WP_Post object to generate the form for. Default current post.
2163  */
2164 function comment_form( $args = array(), $post_id = null ) {
2165         if ( null === $post_id )
2166                 $post_id = get_the_ID();
2167
2168         $commenter = wp_get_current_commenter();
2169         $user = wp_get_current_user();
2170         $user_identity = $user->exists() ? $user->display_name : '';
2171
2172         $args = wp_parse_args( $args );
2173         if ( ! isset( $args['format'] ) )
2174                 $args['format'] = current_theme_supports( 'html5', 'comment-form' ) ? 'html5' : 'xhtml';
2175
2176         $req      = get_option( 'require_name_email' );
2177         $aria_req = ( $req ? " aria-required='true'" : '' );
2178         $html_req = ( $req ? " required='required'" : '' );
2179         $html5    = 'html5' === $args['format'];
2180         $fields   =  array(
2181                 'author' => '<p class="comment-form-author">' . '<label for="author">' . __( 'Name' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
2182                             '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30" maxlength="245"' . $aria_req . $html_req . ' /></p>',
2183                 'email'  => '<p class="comment-form-email"><label for="email">' . __( 'Email' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
2184                             '<input id="email" name="email" ' . ( $html5 ? 'type="email"' : 'type="text"' ) . ' value="' . esc_attr(  $commenter['comment_author_email'] ) . '" size="30" maxlength="100" aria-describedby="email-notes"' . $aria_req . $html_req  . ' /></p>',
2185                 'url'    => '<p class="comment-form-url"><label for="url">' . __( 'Website' ) . '</label> ' .
2186                             '<input id="url" name="url" ' . ( $html5 ? 'type="url"' : 'type="text"' ) . ' value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" maxlength="200" /></p>',
2187         );
2188
2189         $required_text = sprintf( ' ' . __('Required fields are marked %s'), '<span class="required">*</span>' );
2190
2191         /**
2192          * Filters the default comment form fields.
2193          *
2194          * @since 3.0.0
2195          *
2196          * @param array $fields The default comment fields.
2197          */
2198         $fields = apply_filters( 'comment_form_default_fields', $fields );
2199         $defaults = array(
2200                 'fields'               => $fields,
2201                 'comment_field'        => '<p class="comment-form-comment"><label for="comment">' . _x( 'Comment', 'noun' ) . '</label> <textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" aria-required="true" required="required"></textarea></p>',
2202                 /** This filter is documented in wp-includes/link-template.php */
2203                 'must_log_in'          => '<p class="must-log-in">' . sprintf(
2204                                               /* translators: %s: login URL */
2205                                               __( 'You must be <a href="%s">logged in</a> to post a comment.' ),
2206                                               wp_login_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) )
2207                                           ) . '</p>',
2208                 /** This filter is documented in wp-includes/link-template.php */
2209                 'logged_in_as'         => '<p class="logged-in-as">' . sprintf(
2210                                               /* translators: 1: edit user link, 2: accessibility text, 3: user name, 4: logout URL */
2211                                               __( '<a href="%1$s" aria-label="%2$s">Logged in as %3$s</a>. <a href="%4$s">Log out?</a>' ),
2212                                               get_edit_user_link(),
2213                                               /* translators: %s: user name */
2214                                               esc_attr( sprintf( __( 'Logged in as %s. Edit your profile.' ), $user_identity ) ),
2215                                               $user_identity,
2216                                               wp_logout_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) )
2217                                           ) . '</p>',
2218                 'comment_notes_before' => '<p class="comment-notes"><span id="email-notes">' . __( 'Your email address will not be published.' ) . '</span>'. ( $req ? $required_text : '' ) . '</p>',
2219                 'comment_notes_after'  => '',
2220                 'action'               => site_url( '/wp-comments-post.php' ),
2221                 'id_form'              => 'commentform',
2222                 'id_submit'            => 'submit',
2223                 'class_form'           => 'comment-form',
2224                 'class_submit'         => 'submit',
2225                 'name_submit'          => 'submit',
2226                 'title_reply'          => __( 'Leave a Reply' ),
2227                 'title_reply_to'       => __( 'Leave a Reply to %s' ),
2228                 'title_reply_before'   => '<h3 id="reply-title" class="comment-reply-title">',
2229                 'title_reply_after'    => '</h3>',
2230                 'cancel_reply_before'  => ' <small>',
2231                 'cancel_reply_after'   => '</small>',
2232                 'cancel_reply_link'    => __( 'Cancel reply' ),
2233                 'label_submit'         => __( 'Post Comment' ),
2234                 'submit_button'        => '<input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" />',
2235                 'submit_field'         => '<p class="form-submit">%1$s %2$s</p>',
2236                 'format'               => 'xhtml',
2237         );
2238
2239         /**
2240          * Filters the comment form default arguments.
2241          *
2242          * Use {@see 'comment_form_default_fields'} to filter the comment fields.
2243          *
2244          * @since 3.0.0
2245          *
2246          * @param array $defaults The default comment form arguments.
2247          */
2248         $args = wp_parse_args( $args, apply_filters( 'comment_form_defaults', $defaults ) );
2249
2250         // Ensure that the filtered args contain all required default values.
2251         $args = array_merge( $defaults, $args );
2252
2253         if ( comments_open( $post_id ) ) : ?>
2254                 <?php
2255                 /**
2256                  * Fires before the comment form.
2257                  *
2258                  * @since 3.0.0
2259                  */
2260                 do_action( 'comment_form_before' );
2261                 ?>
2262                 <div id="respond" class="comment-respond">
2263                         <?php
2264                         echo $args['title_reply_before'];
2265
2266                         comment_form_title( $args['title_reply'], $args['title_reply_to'] );
2267
2268                         echo $args['cancel_reply_before'];
2269
2270                         cancel_comment_reply_link( $args['cancel_reply_link'] );
2271
2272                         echo $args['cancel_reply_after'];
2273
2274                         echo $args['title_reply_after'];
2275
2276                         if ( get_option( 'comment_registration' ) && !is_user_logged_in() ) :
2277                                 echo $args['must_log_in'];
2278                                 /**
2279                                  * Fires after the HTML-formatted 'must log in after' message in the comment form.
2280                                  *
2281                                  * @since 3.0.0
2282                                  */
2283                                 do_action( 'comment_form_must_log_in_after' );
2284                         else : ?>
2285                                 <form action="<?php echo esc_url( $args['action'] ); ?>" method="post" id="<?php echo esc_attr( $args['id_form'] ); ?>" class="<?php echo esc_attr( $args['class_form'] ); ?>"<?php echo $html5 ? ' novalidate' : ''; ?>>
2286                                         <?php
2287                                         /**
2288                                          * Fires at the top of the comment form, inside the form tag.
2289                                          *
2290                                          * @since 3.0.0
2291                                          */
2292                                         do_action( 'comment_form_top' );
2293
2294                                         if ( is_user_logged_in() ) :
2295                                                 /**
2296                                                  * Filters the 'logged in' message for the comment form for display.
2297                                                  *
2298                                                  * @since 3.0.0
2299                                                  *
2300                                                  * @param string $args_logged_in The logged-in-as HTML-formatted message.
2301                                                  * @param array  $commenter      An array containing the comment author's
2302                                                  *                               username, email, and URL.
2303                                                  * @param string $user_identity  If the commenter is a registered user,
2304                                                  *                               the display name, blank otherwise.
2305                                                  */
2306                                                 echo apply_filters( 'comment_form_logged_in', $args['logged_in_as'], $commenter, $user_identity );
2307
2308                                                 /**
2309                                                  * Fires after the is_user_logged_in() check in the comment form.
2310                                                  *
2311                                                  * @since 3.0.0
2312                                                  *
2313                                                  * @param array  $commenter     An array containing the comment author's
2314                                                  *                              username, email, and URL.
2315                                                  * @param string $user_identity If the commenter is a registered user,
2316                                                  *                              the display name, blank otherwise.
2317                                                  */
2318                                                 do_action( 'comment_form_logged_in_after', $commenter, $user_identity );
2319
2320                                         else :
2321
2322                                                 echo $args['comment_notes_before'];
2323
2324                                         endif;
2325
2326                                         // Prepare an array of all fields, including the textarea
2327                                         $comment_fields = array( 'comment' => $args['comment_field'] ) + (array) $args['fields'];
2328
2329                                         /**
2330                                          * Filters the comment form fields, including the textarea.
2331                                          *
2332                                          * @since 4.4.0
2333                                          *
2334                                          * @param array $comment_fields The comment fields.
2335                                          */
2336                                         $comment_fields = apply_filters( 'comment_form_fields', $comment_fields );
2337
2338                                         // Get an array of field names, excluding the textarea
2339                                         $comment_field_keys = array_diff( array_keys( $comment_fields ), array( 'comment' ) );
2340
2341                                         // Get the first and the last field name, excluding the textarea
2342                                         $first_field = reset( $comment_field_keys );
2343                                         $last_field  = end( $comment_field_keys );
2344
2345                                         foreach ( $comment_fields as $name => $field ) {
2346
2347                                                 if ( 'comment' === $name ) {
2348
2349                                                         /**
2350                                                          * Filters the content of the comment textarea field for display.
2351                                                          *
2352                                                          * @since 3.0.0
2353                                                          *
2354                                                          * @param string $args_comment_field The content of the comment textarea field.
2355                                                          */
2356                                                         echo apply_filters( 'comment_form_field_comment', $field );
2357
2358                                                         echo $args['comment_notes_after'];
2359
2360                                                 } elseif ( ! is_user_logged_in() ) {
2361
2362                                                         if ( $first_field === $name ) {
2363                                                                 /**
2364                                                                  * Fires before the comment fields in the comment form, excluding the textarea.
2365                                                                  *
2366                                                                  * @since 3.0.0
2367                                                                  */
2368                                                                 do_action( 'comment_form_before_fields' );
2369                                                         }
2370
2371                                                         /**
2372                                                          * Filters a comment form field for display.
2373                                                          *
2374                                                          * The dynamic portion of the filter hook, `$name`, refers to the name
2375                                                          * of the comment form field. Such as 'author', 'email', or 'url'.
2376                                                          *
2377                                                          * @since 3.0.0
2378                                                          *
2379                                                          * @param string $field The HTML-formatted output of the comment form field.
2380                                                          */
2381                                                         echo apply_filters( "comment_form_field_{$name}", $field ) . "\n";
2382
2383                                                         if ( $last_field === $name ) {
2384                                                                 /**
2385                                                                  * Fires after the comment fields in the comment form, excluding the textarea.
2386                                                                  *
2387                                                                  * @since 3.0.0
2388                                                                  */
2389                                                                 do_action( 'comment_form_after_fields' );
2390                                                         }
2391                                                 }
2392                                         }
2393
2394                                         $submit_button = sprintf(
2395                                                 $args['submit_button'],
2396                                                 esc_attr( $args['name_submit'] ),
2397                                                 esc_attr( $args['id_submit'] ),
2398                                                 esc_attr( $args['class_submit'] ),
2399                                                 esc_attr( $args['label_submit'] )
2400                                         );
2401
2402                                         /**
2403                                          * Filters the submit button for the comment form to display.
2404                                          *
2405                                          * @since 4.2.0
2406                                          *
2407                                          * @param string $submit_button HTML markup for the submit button.
2408                                          * @param array  $args          Arguments passed to `comment_form()`.
2409                                          */
2410                                         $submit_button = apply_filters( 'comment_form_submit_button', $submit_button, $args );
2411
2412                                         $submit_field = sprintf(
2413                                                 $args['submit_field'],
2414                                                 $submit_button,
2415                                                 get_comment_id_fields( $post_id )
2416                                         );
2417
2418                                         /**
2419                                          * Filters the submit field for the comment form to display.
2420                                          *
2421                                          * The submit field includes the submit button, hidden fields for the
2422                                          * comment form, and any wrapper markup.
2423                                          *
2424                                          * @since 4.2.0
2425                                          *
2426                                          * @param string $submit_field HTML markup for the submit field.
2427                                          * @param array  $args         Arguments passed to comment_form().
2428                                          */
2429                                         echo apply_filters( 'comment_form_submit_field', $submit_field, $args );
2430
2431                                         /**
2432                                          * Fires at the bottom of the comment form, inside the closing </form> tag.
2433                                          *
2434                                          * @since 1.5.0
2435                                          *
2436                                          * @param int $post_id The post ID.
2437                                          */
2438                                         do_action( 'comment_form', $post_id );
2439                                         ?>
2440                                 </form>
2441                         <?php endif; ?>
2442                 </div><!-- #respond -->
2443                 <?php
2444                 /**
2445                  * Fires after the comment form.
2446                  *
2447                  * @since 3.0.0
2448                  */
2449                 do_action( 'comment_form_after' );
2450         else :
2451                 /**
2452                  * Fires after the comment form if comments are closed.
2453                  *
2454                  * @since 3.0.0
2455                  */
2456                 do_action( 'comment_form_comments_closed' );
2457         endif;
2458 }