WordPress 4.7
[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    $max_depth  The max depth of the comment tree. Default 0.
1580  *     @type int    $depth      The depth of the new comment. Must be greater than 0 and less than the value
1581  *                              of the 'thread_comments_depth' option set in Settings > Discussion. Default 0.
1582  *     @type string $before     The text or HTML to add before the reply link. Default empty.
1583  *     @type string $after      The text or HTML to add after the reply link. Default empty.
1584  * }
1585  * @param int|WP_Comment $comment Comment being replied to. Default current comment.
1586  * @param int|WP_Post    $post    Post ID or WP_Post object the comment is going to be displayed on.
1587  *                                Default current post.
1588  * @return void|false|string Link to show comment form, if successful. False, if comments are closed.
1589  */
1590 function get_comment_reply_link( $args = array(), $comment = null, $post = null ) {
1591         $defaults = array(
1592                 'add_below'     => 'comment',
1593                 'respond_id'    => 'respond',
1594                 'reply_text'    => __( 'Reply' ),
1595                 /* translators: Comment reply button text. 1: Comment author name */
1596                 'reply_to_text' => __( 'Reply to %s' ),
1597                 'login_text'    => __( 'Log in to Reply' ),
1598                 'max_depth'     => 0,
1599                 'depth'         => 0,
1600                 'before'        => '',
1601                 'after'         => ''
1602         );
1603
1604         $args = wp_parse_args( $args, $defaults );
1605
1606         if ( 0 == $args['depth'] || $args['max_depth'] <= $args['depth'] ) {
1607                 return;
1608         }
1609
1610         $comment = get_comment( $comment );
1611
1612         if ( empty( $post ) ) {
1613                 $post = $comment->comment_post_ID;
1614         }
1615
1616         $post = get_post( $post );
1617
1618         if ( ! comments_open( $post->ID ) ) {
1619                 return false;
1620         }
1621
1622         /**
1623          * Filters the comment reply link arguments.
1624          *
1625          * @since 4.1.0
1626          *
1627          * @param array      $args    Comment reply link arguments. See get_comment_reply_link()
1628          *                            for more information on accepted arguments.
1629          * @param WP_Comment $comment The object of the comment being replied to.
1630          * @param WP_Post    $post    The WP_Post object.
1631          */
1632         $args = apply_filters( 'comment_reply_link_args', $args, $comment, $post );
1633
1634         if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) {
1635                 $link = sprintf( '<a rel="nofollow" class="comment-reply-login" href="%s">%s</a>',
1636                         esc_url( wp_login_url( get_permalink() ) ),
1637                         $args['login_text']
1638                 );
1639         } else {
1640                 $onclick = sprintf( 'return addComment.moveForm( "%1$s-%2$s", "%2$s", "%3$s", "%4$s" )',
1641                         $args['add_below'], $comment->comment_ID, $args['respond_id'], $post->ID
1642                 );
1643
1644                 $link = sprintf( "<a rel='nofollow' class='comment-reply-link' href='%s' onclick='%s' aria-label='%s'>%s</a>",
1645                         esc_url( add_query_arg( 'replytocom', $comment->comment_ID, get_permalink( $post->ID ) ) ) . "#" . $args['respond_id'],
1646                         $onclick,
1647                         esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ),
1648                         $args['reply_text']
1649                 );
1650         }
1651
1652         /**
1653          * Filters the comment reply link.
1654          *
1655          * @since 2.7.0
1656          *
1657          * @param string  $link    The HTML markup for the comment reply link.
1658          * @param array   $args    An array of arguments overriding the defaults.
1659          * @param object  $comment The object of the comment being replied.
1660          * @param WP_Post $post    The WP_Post object.
1661          */
1662         return apply_filters( 'comment_reply_link', $args['before'] . $link . $args['after'], $args, $comment, $post );
1663 }
1664
1665 /**
1666  * Displays the HTML content for reply to comment link.
1667  *
1668  * @since 2.7.0
1669  *
1670  * @see get_comment_reply_link()
1671  *
1672  * @param array       $args    Optional. Override default options.
1673  * @param int         $comment Comment being replied to. Default current comment.
1674  * @param int|WP_Post $post    Post ID or WP_Post object the comment is going to be displayed on.
1675  *                             Default current post.
1676  * @return mixed Link to show comment form, if successful. False, if comments are closed.
1677  */
1678 function comment_reply_link($args = array(), $comment = null, $post = null) {
1679         echo get_comment_reply_link($args, $comment, $post);
1680 }
1681
1682 /**
1683  * Retrieve HTML content for reply to post link.
1684  *
1685  * @since 2.7.0
1686  *
1687  * @param array $args {
1688  *     Optional. Override default arguments.
1689  *
1690  *     @type string $add_below  The first part of the selector used to identify the comment to respond below.
1691  *                              The resulting value is passed as the first parameter to addComment.moveForm(),
1692  *                              concatenated as $add_below-$comment->comment_ID. Default is 'post'.
1693  *     @type string $respond_id The selector identifying the responding comment. Passed as the third parameter
1694  *                              to addComment.moveForm(), and appended to the link URL as a hash value.
1695  *                              Default 'respond'.
1696  *     @type string $reply_text Text of the Reply link. Default is 'Leave a Comment'.
1697  *     @type string $login_text Text of the link to reply if logged out. Default is 'Log in to leave a Comment'.
1698  *     @type string $before     Text or HTML to add before the reply link. Default empty.
1699  *     @type string $after      Text or HTML to add after the reply link. Default empty.
1700  * }
1701  * @param int|WP_Post $post    Optional. Post ID or WP_Post object the comment is going to be displayed on.
1702  *                             Default current post.
1703  * @return false|null|string Link to show comment form, if successful. False, if comments are closed.
1704  */
1705 function get_post_reply_link($args = array(), $post = null) {
1706         $defaults = array(
1707                 'add_below'  => 'post',
1708                 'respond_id' => 'respond',
1709                 'reply_text' => __('Leave a Comment'),
1710                 'login_text' => __('Log in to leave a Comment'),
1711                 'before'     => '',
1712                 'after'      => '',
1713         );
1714
1715         $args = wp_parse_args($args, $defaults);
1716
1717         $post = get_post($post);
1718
1719         if ( ! comments_open( $post->ID ) ) {
1720                 return false;
1721         }
1722
1723         if ( get_option('comment_registration') && ! is_user_logged_in() ) {
1724                 $link = sprintf( '<a rel="nofollow" class="comment-reply-login" href="%s">%s</a>',
1725                         wp_login_url( get_permalink() ),
1726                         $args['login_text']
1727                 );
1728         } else {
1729                 $onclick = sprintf( 'return addComment.moveForm( "%1$s-%2$s", "0", "%3$s", "%2$s" )',
1730                         $args['add_below'], $post->ID, $args['respond_id']
1731                 );
1732
1733                 $link = sprintf( "<a rel='nofollow' class='comment-reply-link' href='%s' onclick='%s'>%s</a>",
1734                         get_permalink( $post->ID ) . '#' . $args['respond_id'],
1735                         $onclick,
1736                         $args['reply_text']
1737                 );
1738         }
1739         $formatted_link = $args['before'] . $link . $args['after'];
1740
1741         /**
1742          * Filters the formatted post comments link HTML.
1743          *
1744          * @since 2.7.0
1745          *
1746          * @param string      $formatted The HTML-formatted post comments link.
1747          * @param int|WP_Post $post      The post ID or WP_Post object.
1748          */
1749         return apply_filters( 'post_comments_link', $formatted_link, $post );
1750 }
1751
1752 /**
1753  * Displays the HTML content for reply to post link.
1754  *
1755  * @since 2.7.0
1756  *
1757  * @see get_post_reply_link()
1758  *
1759  * @param array       $args Optional. Override default options,
1760  * @param int|WP_Post $post Post ID or WP_Post object the comment is going to be displayed on.
1761  *                          Default current post.
1762  * @return string|bool|null Link to show comment form, if successful. False, if comments are closed.
1763  */
1764 function post_reply_link($args = array(), $post = null) {
1765         echo get_post_reply_link($args, $post);
1766 }
1767
1768 /**
1769  * Retrieve HTML content for cancel comment reply link.
1770  *
1771  * @since 2.7.0
1772  *
1773  * @param string $text Optional. Text to display for cancel reply link. Default empty.
1774  * @return string
1775  */
1776 function get_cancel_comment_reply_link( $text = '' ) {
1777         if ( empty($text) )
1778                 $text = __('Click here to cancel reply.');
1779
1780         $style = isset($_GET['replytocom']) ? '' : ' style="display:none;"';
1781         $link = esc_html( remove_query_arg('replytocom') ) . '#respond';
1782
1783         $formatted_link = '<a rel="nofollow" id="cancel-comment-reply-link" href="' . $link . '"' . $style . '>' . $text . '</a>';
1784
1785         /**
1786          * Filters the cancel comment reply link HTML.
1787          *
1788          * @since 2.7.0
1789          *
1790          * @param string $formatted_link The HTML-formatted cancel comment reply link.
1791          * @param string $link           Cancel comment reply link URL.
1792          * @param string $text           Cancel comment reply link text.
1793          */
1794         return apply_filters( 'cancel_comment_reply_link', $formatted_link, $link, $text );
1795 }
1796
1797 /**
1798  * Display HTML content for cancel comment reply link.
1799  *
1800  * @since 2.7.0
1801  *
1802  * @param string $text Optional. Text to display for cancel reply link. Default empty.
1803  */
1804 function cancel_comment_reply_link( $text = '' ) {
1805         echo get_cancel_comment_reply_link($text);
1806 }
1807
1808 /**
1809  * Retrieve hidden input HTML for replying to comments.
1810  *
1811  * @since 3.0.0
1812  *
1813  * @param int $id Optional. Post ID. Default current post ID.
1814  * @return string Hidden input HTML for replying to comments
1815  */
1816 function get_comment_id_fields( $id = 0 ) {
1817         if ( empty( $id ) )
1818                 $id = get_the_ID();
1819
1820         $replytoid = isset($_GET['replytocom']) ? (int) $_GET['replytocom'] : 0;
1821         $result  = "<input type='hidden' name='comment_post_ID' value='$id' id='comment_post_ID' />\n";
1822         $result .= "<input type='hidden' name='comment_parent' id='comment_parent' value='$replytoid' />\n";
1823
1824         /**
1825          * Filters the returned comment id fields.
1826          *
1827          * @since 3.0.0
1828          *
1829          * @param string $result    The HTML-formatted hidden id field comment elements.
1830          * @param int    $id        The post ID.
1831          * @param int    $replytoid The id of the comment being replied to.
1832          */
1833         return apply_filters( 'comment_id_fields', $result, $id, $replytoid );
1834 }
1835
1836 /**
1837  * Output hidden input HTML for replying to comments.
1838  *
1839  * @since 2.7.0
1840  *
1841  * @param int $id Optional. Post ID. Default current post ID.
1842  */
1843 function comment_id_fields( $id = 0 ) {
1844         echo get_comment_id_fields( $id );
1845 }
1846
1847 /**
1848  * Display text based on comment reply status.
1849  *
1850  * Only affects users with JavaScript disabled.
1851  *
1852  * @internal The $comment global must be present to allow template tags access to the current
1853  *           comment. See https://core.trac.wordpress.org/changeset/36512.
1854  *
1855  * @since 2.7.0
1856  *
1857  * @global WP_Comment $comment Current comment.
1858  *
1859  * @param string $noreplytext  Optional. Text to display when not replying to a comment.
1860  *                             Default false.
1861  * @param string $replytext    Optional. Text to display when replying to a comment.
1862  *                             Default false. Accepts "%s" for the author of the comment
1863  *                             being replied to.
1864  * @param string $linktoparent Optional. Boolean to control making the author's name a link
1865  *                             to their comment. Default true.
1866  */
1867 function comment_form_title( $noreplytext = false, $replytext = false, $linktoparent = true ) {
1868         global $comment;
1869
1870         if ( false === $noreplytext ) $noreplytext = __( 'Leave a Reply' );
1871         if ( false === $replytext ) $replytext = __( 'Leave a Reply to %s' );
1872
1873         $replytoid = isset($_GET['replytocom']) ? (int) $_GET['replytocom'] : 0;
1874
1875         if ( 0 == $replytoid )
1876                 echo $noreplytext;
1877         else {
1878                 // Sets the global so that template tags can be used in the comment form.
1879                 $comment = get_comment($replytoid);
1880                 $author = ( $linktoparent ) ? '<a href="#comment-' . get_comment_ID() . '">' . get_comment_author( $comment ) . '</a>' : get_comment_author( $comment );
1881                 printf( $replytext, $author );
1882         }
1883 }
1884
1885 /**
1886  * List comments.
1887  *
1888  * Used in the comments.php template to list comments for a particular post.
1889  *
1890  * @since 2.7.0
1891  *
1892  * @see WP_Query->comments
1893  *
1894  * @global WP_Query $wp_query
1895  * @global int      $comment_alt
1896  * @global int      $comment_depth
1897  * @global int      $comment_thread_alt
1898  * @global bool     $overridden_cpage
1899  * @global bool     $in_comment_loop
1900  *
1901  * @param string|array $args {
1902  *     Optional. Formatting options.
1903  *
1904  *     @type object $walker            Instance of a Walker class to list comments. Default null.
1905  *     @type int    $max_depth         The maximum comments depth. Default empty.
1906  *     @type string $style             The style of list ordering. Default 'ul'. Accepts 'ul', 'ol'.
1907  *     @type string $callback          Callback function to use. Default null.
1908  *     @type string $end-callback      Callback function to use at the end. Default null.
1909  *     @type string $type              Type of comments to list.
1910  *                                     Default 'all'. Accepts 'all', 'comment', 'pingback', 'trackback', 'pings'.
1911  *     @type int    $page              Page ID to list comments for. Default empty.
1912  *     @type int    $per_page          Number of comments to list per page. Default empty.
1913  *     @type int    $avatar_size       Height and width dimensions of the avatar size. Default 32.
1914  *     @type bool   $reverse_top_level Ordering of the listed comments. If true, will display newest comments first.
1915  *     @type bool   $reverse_children  Whether to reverse child comments in the list. Default null.
1916  *     @type string $format            How to format the comments list.
1917  *                                     Default 'html5' if the theme supports it. Accepts 'html5', 'xhtml'.
1918  *     @type bool   $short_ping        Whether to output short pings. Default false.
1919  *     @type bool   $echo              Whether to echo the output or return it. Default true.
1920  * }
1921  * @param array $comments Optional. Array of WP_Comment objects.
1922  */
1923 function wp_list_comments( $args = array(), $comments = null ) {
1924         global $wp_query, $comment_alt, $comment_depth, $comment_thread_alt, $overridden_cpage, $in_comment_loop;
1925
1926         $in_comment_loop = true;
1927
1928         $comment_alt = $comment_thread_alt = 0;
1929         $comment_depth = 1;
1930
1931         $defaults = array(
1932                 'walker'            => null,
1933                 'max_depth'         => '',
1934                 'style'             => 'ul',
1935                 'callback'          => null,
1936                 'end-callback'      => null,
1937                 'type'              => 'all',
1938                 'page'              => '',
1939                 'per_page'          => '',
1940                 'avatar_size'       => 32,
1941                 'reverse_top_level' => null,
1942                 'reverse_children'  => '',
1943                 'format'            => current_theme_supports( 'html5', 'comment-list' ) ? 'html5' : 'xhtml',
1944                 'short_ping'        => false,
1945                 'echo'              => true,
1946         );
1947
1948         $r = wp_parse_args( $args, $defaults );
1949
1950         /**
1951          * Filters the arguments used in retrieving the comment list.
1952          *
1953          * @since 4.0.0
1954          *
1955          * @see wp_list_comments()
1956          *
1957          * @param array $r An array of arguments for displaying comments.
1958          */
1959         $r = apply_filters( 'wp_list_comments_args', $r );
1960
1961         // Figure out what comments we'll be looping through ($_comments)
1962         if ( null !== $comments ) {
1963                 $comments = (array) $comments;
1964                 if ( empty($comments) )
1965                         return;
1966                 if ( 'all' != $r['type'] ) {
1967                         $comments_by_type = separate_comments($comments);
1968                         if ( empty($comments_by_type[$r['type']]) )
1969                                 return;
1970                         $_comments = $comments_by_type[$r['type']];
1971                 } else {
1972                         $_comments = $comments;
1973                 }
1974         } else {
1975                 /*
1976                  * If 'page' or 'per_page' has been passed, and does not match what's in $wp_query,
1977                  * perform a separate comment query and allow Walker_Comment to paginate.
1978                  */
1979                 if ( $r['page'] || $r['per_page'] ) {
1980                         $current_cpage = get_query_var( 'cpage' );
1981                         if ( ! $current_cpage ) {
1982                                 $current_cpage = 'newest' === get_option( 'default_comments_page' ) ? 1 : $wp_query->max_num_comment_pages;
1983                         }
1984
1985                         $current_per_page = get_query_var( 'comments_per_page' );
1986                         if ( $r['page'] != $current_cpage || $r['per_page'] != $current_per_page ) {
1987                                 $comment_args = array(
1988                                         'post_id' => get_the_ID(),
1989                                         'orderby' => 'comment_date_gmt',
1990                                         'order' => 'ASC',
1991                                         'status' => 'approve',
1992                                 );
1993
1994                                 if ( is_user_logged_in() ) {
1995                                         $comment_args['include_unapproved'] = get_current_user_id();
1996                                 } else {
1997                                         $commenter = wp_get_current_commenter();
1998                                         if ( $commenter['comment_author_email'] ) {
1999                                                 $comment_args['include_unapproved'] = $commenter['comment_author_email'];
2000                                         }
2001                                 }
2002
2003                                 $comments = get_comments( $comment_args );
2004
2005                                 if ( 'all' != $r['type'] ) {
2006                                         $comments_by_type = separate_comments( $comments );
2007                                         if ( empty( $comments_by_type[ $r['type'] ] ) ) {
2008                                                 return;
2009                                         }
2010
2011                                         $_comments = $comments_by_type[ $r['type'] ];
2012                                 } else {
2013                                         $_comments = $comments;
2014                                 }
2015                         }
2016
2017                 // Otherwise, fall back on the comments from `$wp_query->comments`.
2018                 } else {
2019                         if ( empty($wp_query->comments) )
2020                                 return;
2021                         if ( 'all' != $r['type'] ) {
2022                                 if ( empty($wp_query->comments_by_type) )
2023                                         $wp_query->comments_by_type = separate_comments($wp_query->comments);
2024                                 if ( empty($wp_query->comments_by_type[$r['type']]) )
2025                                         return;
2026                                 $_comments = $wp_query->comments_by_type[$r['type']];
2027                         } else {
2028                                 $_comments = $wp_query->comments;
2029                         }
2030
2031                         if ( $wp_query->max_num_comment_pages ) {
2032                                 $default_comments_page = get_option( 'default_comments_page' );
2033                                 $cpage = get_query_var( 'cpage' );
2034                                 if ( 'newest' === $default_comments_page ) {
2035                                         $r['cpage'] = $cpage;
2036
2037                                 /*
2038                                  * When first page shows oldest comments, post permalink is the same as
2039                                  * the comment permalink.
2040                                  */
2041                                 } elseif ( $cpage == 1 ) {
2042                                         $r['cpage'] = '';
2043                                 } else {
2044                                         $r['cpage'] = $cpage;
2045                                 }
2046
2047                                 $r['page'] = 0;
2048                                 $r['per_page'] = 0;
2049                         }
2050                 }
2051         }
2052
2053         if ( '' === $r['per_page'] && get_option( 'page_comments' ) ) {
2054                 $r['per_page'] = get_query_var('comments_per_page');
2055         }
2056
2057         if ( empty($r['per_page']) ) {
2058                 $r['per_page'] = 0;
2059                 $r['page'] = 0;
2060         }
2061
2062         if ( '' === $r['max_depth'] ) {
2063                 if ( get_option('thread_comments') )
2064                         $r['max_depth'] = get_option('thread_comments_depth');
2065                 else
2066                         $r['max_depth'] = -1;
2067         }
2068
2069         if ( '' === $r['page'] ) {
2070                 if ( empty($overridden_cpage) ) {
2071                         $r['page'] = get_query_var('cpage');
2072                 } else {
2073                         $threaded = ( -1 != $r['max_depth'] );
2074                         $r['page'] = ( 'newest' == get_option('default_comments_page') ) ? get_comment_pages_count($_comments, $r['per_page'], $threaded) : 1;
2075                         set_query_var( 'cpage', $r['page'] );
2076                 }
2077         }
2078         // Validation check
2079         $r['page'] = intval($r['page']);
2080         if ( 0 == $r['page'] && 0 != $r['per_page'] )
2081                 $r['page'] = 1;
2082
2083         if ( null === $r['reverse_top_level'] )
2084                 $r['reverse_top_level'] = ( 'desc' == get_option('comment_order') );
2085
2086         wp_queue_comments_for_comment_meta_lazyload( $_comments );
2087
2088         if ( empty( $r['walker'] ) ) {
2089                 $walker = new Walker_Comment;
2090         } else {
2091                 $walker = $r['walker'];
2092         }
2093
2094         $output = $walker->paged_walk( $_comments, $r['max_depth'], $r['page'], $r['per_page'], $r );
2095
2096         $in_comment_loop = false;
2097
2098         if ( $r['echo'] ) {
2099                 echo $output;
2100         } else {
2101                 return $output;
2102         }
2103 }
2104
2105 /**
2106  * Outputs a complete commenting form for use within a template.
2107  *
2108  * Most strings and form fields may be controlled through the $args array passed
2109  * into the function, while you may also choose to use the {@see 'comment_form_default_fields'}
2110  * filter to modify the array of default fields if you'd just like to add a new
2111  * one or remove a single field. All fields are also individually passed through
2112  * a filter of the {@see 'comment_form_field_$name'} where $name is the key used
2113  * in the array of fields.
2114  *
2115  * @since 3.0.0
2116  * @since 4.1.0 Introduced the 'class_submit' argument.
2117  * @since 4.2.0 Introduced the 'submit_button' and 'submit_fields' arguments.
2118  * @since 4.4.0 Introduced the 'class_form', 'title_reply_before', 'title_reply_after',
2119  *              'cancel_reply_before', and 'cancel_reply_after' arguments.
2120  * @since 4.5.0 The 'author', 'email', and 'url' form fields are limited to 245, 100,
2121  *              and 200 characters, respectively.
2122  * @since 4.6.0 Introduced the 'action' argument.
2123  *
2124  * @param array       $args {
2125  *     Optional. Default arguments and form fields to override.
2126  *
2127  *     @type array $fields {
2128  *         Default comment fields, filterable by default via the {@see 'comment_form_default_fields'} hook.
2129  *
2130  *         @type string $author Comment author field HTML.
2131  *         @type string $email  Comment author email field HTML.
2132  *         @type string $url    Comment author URL field HTML.
2133  *     }
2134  *     @type string $comment_field        The comment textarea field HTML.
2135  *     @type string $must_log_in          HTML element for a 'must be logged in to comment' message.
2136  *     @type string $logged_in_as         HTML element for a 'logged in as [user]' message.
2137  *     @type string $comment_notes_before HTML element for a message displayed before the comment fields
2138  *                                        if the user is not logged in.
2139  *                                        Default 'Your email address will not be published.'.
2140  *     @type string $comment_notes_after  HTML element for a message displayed after the textarea field.
2141  *     @type string $action               The comment form element action attribute. Default '/wp-comments-post.php'.
2142  *     @type string $id_form              The comment form element id attribute. Default 'commentform'.
2143  *     @type string $id_submit            The comment submit element id attribute. Default 'submit'.
2144  *     @type string $class_form           The comment form element class attribute. Default 'comment-form'.
2145  *     @type string $class_submit         The comment submit element class attribute. Default 'submit'.
2146  *     @type string $name_submit          The comment submit element name attribute. Default 'submit'.
2147  *     @type string $title_reply          The translatable 'reply' button label. Default 'Leave a Reply'.
2148  *     @type string $title_reply_to       The translatable 'reply-to' button label. Default 'Leave a Reply to %s',
2149  *                                        where %s is the author of the comment being replied to.
2150  *     @type string $title_reply_before   HTML displayed before the comment form title.
2151  *                                        Default: '<h3 id="reply-title" class="comment-reply-title">'.
2152  *     @type string $title_reply_after    HTML displayed after the comment form title.
2153  *                                        Default: '</h3>'.
2154  *     @type string $cancel_reply_before  HTML displayed before the cancel reply link.
2155  *     @type string $cancel_reply_after   HTML displayed after the cancel reply link.
2156  *     @type string $cancel_reply_link    The translatable 'cancel reply' button label. Default 'Cancel reply'.
2157  *     @type string $label_submit         The translatable 'submit' button label. Default 'Post a comment'.
2158  *     @type string $submit_button        HTML format for the Submit button.
2159  *                                        Default: '<input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" />'.
2160  *     @type string $submit_field         HTML format for the markup surrounding the Submit button and comment hidden
2161  *                                        fields. Default: '<p class="form-submit">%1$s %2$s</a>', where %1$s is the
2162  *                                        submit button markup and %2$s is the comment hidden fields.
2163  *     @type string $format               The comment form format. Default 'xhtml'. Accepts 'xhtml', 'html5'.
2164  * }
2165  * @param int|WP_Post $post_id Post ID or WP_Post object to generate the form for. Default current post.
2166  */
2167 function comment_form( $args = array(), $post_id = null ) {
2168         if ( null === $post_id )
2169                 $post_id = get_the_ID();
2170
2171         // Exit the function when comments for the post are closed.
2172         if ( ! comments_open( $post_id ) ) {
2173                 /**
2174                  * Fires after the comment form if comments are closed.
2175                  *
2176                  * @since 3.0.0
2177                  */
2178                 do_action( 'comment_form_comments_closed' );
2179
2180                 return;
2181         }
2182
2183         $commenter = wp_get_current_commenter();
2184         $user = wp_get_current_user();
2185         $user_identity = $user->exists() ? $user->display_name : '';
2186
2187         $args = wp_parse_args( $args );
2188         if ( ! isset( $args['format'] ) )
2189                 $args['format'] = current_theme_supports( 'html5', 'comment-form' ) ? 'html5' : 'xhtml';
2190
2191         $req      = get_option( 'require_name_email' );
2192         $aria_req = ( $req ? " aria-required='true'" : '' );
2193         $html_req = ( $req ? " required='required'" : '' );
2194         $html5    = 'html5' === $args['format'];
2195         $fields   =  array(
2196                 'author' => '<p class="comment-form-author">' . '<label for="author">' . __( 'Name' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
2197                             '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30" maxlength="245"' . $aria_req . $html_req . ' /></p>',
2198                 'email'  => '<p class="comment-form-email"><label for="email">' . __( 'Email' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
2199                             '<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>',
2200                 'url'    => '<p class="comment-form-url"><label for="url">' . __( 'Website' ) . '</label> ' .
2201                             '<input id="url" name="url" ' . ( $html5 ? 'type="url"' : 'type="text"' ) . ' value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" maxlength="200" /></p>',
2202         );
2203
2204         $required_text = sprintf( ' ' . __('Required fields are marked %s'), '<span class="required">*</span>' );
2205
2206         /**
2207          * Filters the default comment form fields.
2208          *
2209          * @since 3.0.0
2210          *
2211          * @param array $fields The default comment fields.
2212          */
2213         $fields = apply_filters( 'comment_form_default_fields', $fields );
2214         $defaults = array(
2215                 'fields'               => $fields,
2216                 '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>',
2217                 /** This filter is documented in wp-includes/link-template.php */
2218                 'must_log_in'          => '<p class="must-log-in">' . sprintf(
2219                                               /* translators: %s: login URL */
2220                                               __( 'You must be <a href="%s">logged in</a> to post a comment.' ),
2221                                               wp_login_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) )
2222                                           ) . '</p>',
2223                 /** This filter is documented in wp-includes/link-template.php */
2224                 'logged_in_as'         => '<p class="logged-in-as">' . sprintf(
2225                                               /* translators: 1: edit user link, 2: accessibility text, 3: user name, 4: logout URL */
2226                                               __( '<a href="%1$s" aria-label="%2$s">Logged in as %3$s</a>. <a href="%4$s">Log out?</a>' ),
2227                                               get_edit_user_link(),
2228                                               /* translators: %s: user name */
2229                                               esc_attr( sprintf( __( 'Logged in as %s. Edit your profile.' ), $user_identity ) ),
2230                                               $user_identity,
2231                                               wp_logout_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) )
2232                                           ) . '</p>',
2233                 'comment_notes_before' => '<p class="comment-notes"><span id="email-notes">' . __( 'Your email address will not be published.' ) . '</span>'. ( $req ? $required_text : '' ) . '</p>',
2234                 'comment_notes_after'  => '',
2235                 'action'               => site_url( '/wp-comments-post.php' ),
2236                 'id_form'              => 'commentform',
2237                 'id_submit'            => 'submit',
2238                 'class_form'           => 'comment-form',
2239                 'class_submit'         => 'submit',
2240                 'name_submit'          => 'submit',
2241                 'title_reply'          => __( 'Leave a Reply' ),
2242                 'title_reply_to'       => __( 'Leave a Reply to %s' ),
2243                 'title_reply_before'   => '<h3 id="reply-title" class="comment-reply-title">',
2244                 'title_reply_after'    => '</h3>',
2245                 'cancel_reply_before'  => ' <small>',
2246                 'cancel_reply_after'   => '</small>',
2247                 'cancel_reply_link'    => __( 'Cancel reply' ),
2248                 'label_submit'         => __( 'Post Comment' ),
2249                 'submit_button'        => '<input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" />',
2250                 'submit_field'         => '<p class="form-submit">%1$s %2$s</p>',
2251                 'format'               => 'xhtml',
2252         );
2253
2254         /**
2255          * Filters the comment form default arguments.
2256          *
2257          * Use {@see 'comment_form_default_fields'} to filter the comment fields.
2258          *
2259          * @since 3.0.0
2260          *
2261          * @param array $defaults The default comment form arguments.
2262          */
2263         $args = wp_parse_args( $args, apply_filters( 'comment_form_defaults', $defaults ) );
2264
2265         // Ensure that the filtered args contain all required default values.
2266         $args = array_merge( $defaults, $args );
2267
2268         /**
2269          * Fires before the comment form.
2270          *
2271          * @since 3.0.0
2272          */
2273         do_action( 'comment_form_before' );
2274         ?>
2275         <div id="respond" class="comment-respond">
2276                 <?php
2277                 echo $args['title_reply_before'];
2278
2279                 comment_form_title( $args['title_reply'], $args['title_reply_to'] );
2280
2281                 echo $args['cancel_reply_before'];
2282
2283                 cancel_comment_reply_link( $args['cancel_reply_link'] );
2284
2285                 echo $args['cancel_reply_after'];
2286
2287                 echo $args['title_reply_after'];
2288
2289                 if ( get_option( 'comment_registration' ) && !is_user_logged_in() ) :
2290                         echo $args['must_log_in'];
2291                         /**
2292                          * Fires after the HTML-formatted 'must log in after' message in the comment form.
2293                          *
2294                          * @since 3.0.0
2295                          */
2296                         do_action( 'comment_form_must_log_in_after' );
2297                 else : ?>
2298                         <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' : ''; ?>>
2299                                 <?php
2300                                 /**
2301                                  * Fires at the top of the comment form, inside the form tag.
2302                                  *
2303                                  * @since 3.0.0
2304                                  */
2305                                 do_action( 'comment_form_top' );
2306
2307                                 if ( is_user_logged_in() ) :
2308                                         /**
2309                                          * Filters the 'logged in' message for the comment form for display.
2310                                          *
2311                                          * @since 3.0.0
2312                                          *
2313                                          * @param string $args_logged_in The logged-in-as HTML-formatted message.
2314                                          * @param array  $commenter      An array containing the comment author's
2315                                          *                               username, email, and URL.
2316                                          * @param string $user_identity  If the commenter is a registered user,
2317                                          *                               the display name, blank otherwise.
2318                                          */
2319                                         echo apply_filters( 'comment_form_logged_in', $args['logged_in_as'], $commenter, $user_identity );
2320
2321                                         /**
2322                                          * Fires after the is_user_logged_in() check in the comment form.
2323                                          *
2324                                          * @since 3.0.0
2325                                          *
2326                                          * @param array  $commenter     An array containing the comment author's
2327                                          *                              username, email, and URL.
2328                                          * @param string $user_identity If the commenter is a registered user,
2329                                          *                              the display name, blank otherwise.
2330                                          */
2331                                         do_action( 'comment_form_logged_in_after', $commenter, $user_identity );
2332
2333                                 else :
2334
2335                                         echo $args['comment_notes_before'];
2336
2337                                 endif;
2338
2339                                 // Prepare an array of all fields, including the textarea
2340                                 $comment_fields = array( 'comment' => $args['comment_field'] ) + (array) $args['fields'];
2341
2342                                 /**
2343                                  * Filters the comment form fields, including the textarea.
2344                                  *
2345                                  * @since 4.4.0
2346                                  *
2347                                  * @param array $comment_fields The comment fields.
2348                                  */
2349                                 $comment_fields = apply_filters( 'comment_form_fields', $comment_fields );
2350
2351                                 // Get an array of field names, excluding the textarea
2352                                 $comment_field_keys = array_diff( array_keys( $comment_fields ), array( 'comment' ) );
2353
2354                                 // Get the first and the last field name, excluding the textarea
2355                                 $first_field = reset( $comment_field_keys );
2356                                 $last_field  = end( $comment_field_keys );
2357
2358                                 foreach ( $comment_fields as $name => $field ) {
2359
2360                                         if ( 'comment' === $name ) {
2361
2362                                                 /**
2363                                                  * Filters the content of the comment textarea field for display.
2364                                                  *
2365                                                  * @since 3.0.0
2366                                                  *
2367                                                  * @param string $args_comment_field The content of the comment textarea field.
2368                                                  */
2369                                                 echo apply_filters( 'comment_form_field_comment', $field );
2370
2371                                                 echo $args['comment_notes_after'];
2372
2373                                         } elseif ( ! is_user_logged_in() ) {
2374
2375                                                 if ( $first_field === $name ) {
2376                                                         /**
2377                                                          * Fires before the comment fields in the comment form, excluding the textarea.
2378                                                          *
2379                                                          * @since 3.0.0
2380                                                          */
2381                                                         do_action( 'comment_form_before_fields' );
2382                                                 }
2383
2384                                                 /**
2385                                                  * Filters a comment form field for display.
2386                                                  *
2387                                                  * The dynamic portion of the filter hook, `$name`, refers to the name
2388                                                  * of the comment form field. Such as 'author', 'email', or 'url'.
2389                                                  *
2390                                                  * @since 3.0.0
2391                                                  *
2392                                                  * @param string $field The HTML-formatted output of the comment form field.
2393                                                  */
2394                                                 echo apply_filters( "comment_form_field_{$name}", $field ) . "\n";
2395
2396                                                 if ( $last_field === $name ) {
2397                                                         /**
2398                                                          * Fires after the comment fields in the comment form, excluding the textarea.
2399                                                          *
2400                                                          * @since 3.0.0
2401                                                          */
2402                                                         do_action( 'comment_form_after_fields' );
2403                                                 }
2404                                         }
2405                                 }
2406
2407                                 $submit_button = sprintf(
2408                                         $args['submit_button'],
2409                                         esc_attr( $args['name_submit'] ),
2410                                         esc_attr( $args['id_submit'] ),
2411                                         esc_attr( $args['class_submit'] ),
2412                                         esc_attr( $args['label_submit'] )
2413                                 );
2414
2415                                 /**
2416                                  * Filters the submit button for the comment form to display.
2417                                  *
2418                                  * @since 4.2.0
2419                                  *
2420                                  * @param string $submit_button HTML markup for the submit button.
2421                                  * @param array  $args          Arguments passed to `comment_form()`.
2422                                  */
2423                                 $submit_button = apply_filters( 'comment_form_submit_button', $submit_button, $args );
2424
2425                                 $submit_field = sprintf(
2426                                         $args['submit_field'],
2427                                         $submit_button,
2428                                         get_comment_id_fields( $post_id )
2429                                 );
2430
2431                                 /**
2432                                  * Filters the submit field for the comment form to display.
2433                                  *
2434                                  * The submit field includes the submit button, hidden fields for the
2435                                  * comment form, and any wrapper markup.
2436                                  *
2437                                  * @since 4.2.0
2438                                  *
2439                                  * @param string $submit_field HTML markup for the submit field.
2440                                  * @param array  $args         Arguments passed to comment_form().
2441                                  */
2442                                 echo apply_filters( 'comment_form_submit_field', $submit_field, $args );
2443
2444                                 /**
2445                                  * Fires at the bottom of the comment form, inside the closing </form> tag.
2446                                  *
2447                                  * @since 1.5.0
2448                                  *
2449                                  * @param int $post_id The post ID.
2450                                  */
2451                                 do_action( 'comment_form', $post_id );
2452                                 ?>
2453                         </form>
2454                 <?php endif; ?>
2455         </div><!-- #respond -->
2456         <?php
2457
2458         /**
2459          * Fires after the comment form.
2460          *
2461          * @since 3.0.0
2462          */
2463         do_action( 'comment_form_after' );
2464 }