PageRenderTime 56ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-includes/class-walker-comment.php

https://github.com/markjaquith/WordPress
PHP | 492 lines | 274 code | 44 blank | 174 comment | 45 complexity | ca67a3197b5b3df04e08d5f6ba6bc774 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1
  1. <?php
  2. /**
  3. * Comment API: Walker_Comment class
  4. *
  5. * @package WordPress
  6. * @subpackage Comments
  7. * @since 4.4.0
  8. */
  9. /**
  10. * Core walker class used to create an HTML list of comments.
  11. *
  12. * @since 2.7.0
  13. *
  14. * @see Walker
  15. */
  16. class Walker_Comment extends Walker {
  17. /**
  18. * What the class handles.
  19. *
  20. * @since 2.7.0
  21. * @var string
  22. *
  23. * @see Walker::$tree_type
  24. */
  25. public $tree_type = 'comment';
  26. /**
  27. * Database fields to use.
  28. *
  29. * @since 2.7.0
  30. * @var string[]
  31. *
  32. * @see Walker::$db_fields
  33. * @todo Decouple this
  34. */
  35. public $db_fields = array(
  36. 'parent' => 'comment_parent',
  37. 'id' => 'comment_ID',
  38. );
  39. /**
  40. * Starts the list before the elements are added.
  41. *
  42. * @since 2.7.0
  43. *
  44. * @see Walker::start_lvl()
  45. * @global int $comment_depth
  46. *
  47. * @param string $output Used to append additional content (passed by reference).
  48. * @param int $depth Optional. Depth of the current comment. Default 0.
  49. * @param array $args Optional. Uses 'style' argument for type of HTML list. Default empty array.
  50. */
  51. public function start_lvl( &$output, $depth = 0, $args = array() ) {
  52. $GLOBALS['comment_depth'] = $depth + 1;
  53. switch ( $args['style'] ) {
  54. case 'div':
  55. break;
  56. case 'ol':
  57. $output .= '<ol class="children">' . "\n";
  58. break;
  59. case 'ul':
  60. default:
  61. $output .= '<ul class="children">' . "\n";
  62. break;
  63. }
  64. }
  65. /**
  66. * Ends the list of items after the elements are added.
  67. *
  68. * @since 2.7.0
  69. *
  70. * @see Walker::end_lvl()
  71. * @global int $comment_depth
  72. *
  73. * @param string $output Used to append additional content (passed by reference).
  74. * @param int $depth Optional. Depth of the current comment. Default 0.
  75. * @param array $args Optional. Will only append content if style argument value is 'ol' or 'ul'.
  76. * Default empty array.
  77. */
  78. public function end_lvl( &$output, $depth = 0, $args = array() ) {
  79. $GLOBALS['comment_depth'] = $depth + 1;
  80. switch ( $args['style'] ) {
  81. case 'div':
  82. break;
  83. case 'ol':
  84. $output .= "</ol><!-- .children -->\n";
  85. break;
  86. case 'ul':
  87. default:
  88. $output .= "</ul><!-- .children -->\n";
  89. break;
  90. }
  91. }
  92. /**
  93. * Traverses elements to create list from elements.
  94. *
  95. * This function is designed to enhance Walker::display_element() to
  96. * display children of higher nesting levels than selected inline on
  97. * the highest depth level displayed. This prevents them being orphaned
  98. * at the end of the comment list.
  99. *
  100. * Example: max_depth = 2, with 5 levels of nested content.
  101. * 1
  102. * 1.1
  103. * 1.1.1
  104. * 1.1.1.1
  105. * 1.1.1.1.1
  106. * 1.1.2
  107. * 1.1.2.1
  108. * 2
  109. * 2.2
  110. *
  111. * @since 2.7.0
  112. *
  113. * @see Walker::display_element()
  114. * @see wp_list_comments()
  115. *
  116. * @param WP_Comment $element Comment data object.
  117. * @param array $children_elements List of elements to continue traversing. Passed by reference.
  118. * @param int $max_depth Max depth to traverse.
  119. * @param int $depth Depth of the current element.
  120. * @param array $args An array of arguments.
  121. * @param string $output Used to append additional content. Passed by reference.
  122. */
  123. public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
  124. if ( ! $element ) {
  125. return;
  126. }
  127. $id_field = $this->db_fields['id'];
  128. $id = $element->$id_field;
  129. parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
  130. /*
  131. * If at the max depth, and the current element still has children, loop over those
  132. * and display them at this level. This is to prevent them being orphaned to the end
  133. * of the list.
  134. */
  135. if ( $max_depth <= $depth + 1 && isset( $children_elements[ $id ] ) ) {
  136. foreach ( $children_elements[ $id ] as $child ) {
  137. $this->display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
  138. }
  139. unset( $children_elements[ $id ] );
  140. }
  141. }
  142. /**
  143. * Starts the element output.
  144. *
  145. * @since 2.7.0
  146. * @since 5.9.0 Renamed `$comment` to `$data_object` and `$id` to `$current_object_id`
  147. * to match parent class for PHP 8 named parameter support.
  148. *
  149. * @see Walker::start_el()
  150. * @see wp_list_comments()
  151. * @global int $comment_depth
  152. * @global WP_Comment $comment Global comment object.
  153. *
  154. * @param string $output Used to append additional content. Passed by reference.
  155. * @param WP_Comment $data_object Comment data object.
  156. * @param int $depth Optional. Depth of the current comment in reference to parents. Default 0.
  157. * @param array $args Optional. An array of arguments. Default empty array.
  158. * @param int $current_object_id Optional. ID of the current comment. Default 0.
  159. */
  160. public function start_el( &$output, $data_object, $depth = 0, $args = array(), $current_object_id = 0 ) {
  161. // Restores the more descriptive, specific name for use within this method.
  162. $comment = $data_object;
  163. $depth++;
  164. $GLOBALS['comment_depth'] = $depth;
  165. $GLOBALS['comment'] = $comment;
  166. if ( ! empty( $args['callback'] ) ) {
  167. ob_start();
  168. call_user_func( $args['callback'], $comment, $args, $depth );
  169. $output .= ob_get_clean();
  170. return;
  171. }
  172. if ( 'comment' === $comment->comment_type ) {
  173. add_filter( 'comment_text', array( $this, 'filter_comment_text' ), 40, 2 );
  174. }
  175. if ( ( 'pingback' === $comment->comment_type || 'trackback' === $comment->comment_type ) && $args['short_ping'] ) {
  176. ob_start();
  177. $this->ping( $comment, $depth, $args );
  178. $output .= ob_get_clean();
  179. } elseif ( 'html5' === $args['format'] ) {
  180. ob_start();
  181. $this->html5_comment( $comment, $depth, $args );
  182. $output .= ob_get_clean();
  183. } else {
  184. ob_start();
  185. $this->comment( $comment, $depth, $args );
  186. $output .= ob_get_clean();
  187. }
  188. if ( 'comment' === $comment->comment_type ) {
  189. remove_filter( 'comment_text', array( $this, 'filter_comment_text' ), 40 );
  190. }
  191. }
  192. /**
  193. * Ends the element output, if needed.
  194. *
  195. * @since 2.7.0
  196. * @since 5.9.0 Renamed `$comment` to `$data_object` to match parent class for PHP 8 named parameter support.
  197. *
  198. * @see Walker::end_el()
  199. * @see wp_list_comments()
  200. *
  201. * @param string $output Used to append additional content. Passed by reference.
  202. * @param WP_Comment $data_object Comment data object.
  203. * @param int $depth Optional. Depth of the current comment. Default 0.
  204. * @param array $args Optional. An array of arguments. Default empty array.
  205. */
  206. public function end_el( &$output, $data_object, $depth = 0, $args = array() ) {
  207. if ( ! empty( $args['end-callback'] ) ) {
  208. ob_start();
  209. call_user_func(
  210. $args['end-callback'],
  211. $data_object, // The current comment object.
  212. $args,
  213. $depth
  214. );
  215. $output .= ob_get_clean();
  216. return;
  217. }
  218. if ( 'div' === $args['style'] ) {
  219. $output .= "</div><!-- #comment-## -->\n";
  220. } else {
  221. $output .= "</li><!-- #comment-## -->\n";
  222. }
  223. }
  224. /**
  225. * Outputs a pingback comment.
  226. *
  227. * @since 3.6.0
  228. *
  229. * @see wp_list_comments()
  230. *
  231. * @param WP_Comment $comment The comment object.
  232. * @param int $depth Depth of the current comment.
  233. * @param array $args An array of arguments.
  234. */
  235. protected function ping( $comment, $depth, $args ) {
  236. $tag = ( 'div' === $args['style'] ) ? 'div' : 'li';
  237. ?>
  238. <<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class( '', $comment ); ?>>
  239. <div class="comment-body">
  240. <?php _e( 'Pingback:' ); ?> <?php comment_author_link( $comment ); ?> <?php edit_comment_link( __( 'Edit' ), '<span class="edit-link">', '</span>' ); ?>
  241. </div>
  242. <?php
  243. }
  244. /**
  245. * Filters the comment text.
  246. *
  247. * Removes links from the pending comment's text if the commenter did not consent
  248. * to the comment cookies.
  249. *
  250. * @since 5.4.2
  251. *
  252. * @param string $comment_text Text of the current comment.
  253. * @param WP_Comment|null $comment The comment object. Null if not found.
  254. * @return string Filtered text of the current comment.
  255. */
  256. public function filter_comment_text( $comment_text, $comment ) {
  257. $commenter = wp_get_current_commenter();
  258. $show_pending_links = ! empty( $commenter['comment_author'] );
  259. if ( $comment && '0' == $comment->comment_approved && ! $show_pending_links ) {
  260. $comment_text = wp_kses( $comment_text, array() );
  261. }
  262. return $comment_text;
  263. }
  264. /**
  265. * Outputs a single comment.
  266. *
  267. * @since 3.6.0
  268. *
  269. * @see wp_list_comments()
  270. *
  271. * @param WP_Comment $comment Comment to display.
  272. * @param int $depth Depth of the current comment.
  273. * @param array $args An array of arguments.
  274. */
  275. protected function comment( $comment, $depth, $args ) {
  276. if ( 'div' === $args['style'] ) {
  277. $tag = 'div';
  278. $add_below = 'comment';
  279. } else {
  280. $tag = 'li';
  281. $add_below = 'div-comment';
  282. }
  283. $commenter = wp_get_current_commenter();
  284. $show_pending_links = isset( $commenter['comment_author'] ) && $commenter['comment_author'];
  285. if ( $commenter['comment_author_email'] ) {
  286. $moderation_note = __( 'Your comment is awaiting moderation.' );
  287. } else {
  288. $moderation_note = __( 'Your comment is awaiting moderation. This is a preview; your comment will be visible after it has been approved.' );
  289. }
  290. ?>
  291. <<?php echo $tag; ?> <?php comment_class( $this->has_children ? 'parent' : '', $comment ); ?> id="comment-<?php comment_ID(); ?>">
  292. <?php if ( 'div' !== $args['style'] ) : ?>
  293. <div id="div-comment-<?php comment_ID(); ?>" class="comment-body">
  294. <?php endif; ?>
  295. <div class="comment-author vcard">
  296. <?php
  297. if ( 0 != $args['avatar_size'] ) {
  298. echo get_avatar( $comment, $args['avatar_size'] );
  299. }
  300. ?>
  301. <?php
  302. $comment_author = get_comment_author_link( $comment );
  303. if ( '0' == $comment->comment_approved && ! $show_pending_links ) {
  304. $comment_author = get_comment_author( $comment );
  305. }
  306. printf(
  307. /* translators: %s: Comment author link. */
  308. __( '%s <span class="says">says:</span>' ),
  309. sprintf( '<cite class="fn">%s</cite>', $comment_author )
  310. );
  311. ?>
  312. </div>
  313. <?php if ( '0' == $comment->comment_approved ) : ?>
  314. <em class="comment-awaiting-moderation"><?php echo $moderation_note; ?></em>
  315. <br />
  316. <?php endif; ?>
  317. <div class="comment-meta commentmetadata">
  318. <?php
  319. printf(
  320. '<a href="%s">%s</a>',
  321. esc_url( get_comment_link( $comment, $args ) ),
  322. sprintf(
  323. /* translators: 1: Comment date, 2: Comment time. */
  324. __( '%1$s at %2$s' ),
  325. get_comment_date( '', $comment ),
  326. get_comment_time()
  327. )
  328. );
  329. edit_comment_link( __( '(Edit)' ), ' &nbsp;&nbsp;', '' );
  330. ?>
  331. </div>
  332. <?php
  333. comment_text(
  334. $comment,
  335. array_merge(
  336. $args,
  337. array(
  338. 'add_below' => $add_below,
  339. 'depth' => $depth,
  340. 'max_depth' => $args['max_depth'],
  341. )
  342. )
  343. );
  344. ?>
  345. <?php
  346. comment_reply_link(
  347. array_merge(
  348. $args,
  349. array(
  350. 'add_below' => $add_below,
  351. 'depth' => $depth,
  352. 'max_depth' => $args['max_depth'],
  353. 'before' => '<div class="reply">',
  354. 'after' => '</div>',
  355. )
  356. )
  357. );
  358. ?>
  359. <?php if ( 'div' !== $args['style'] ) : ?>
  360. </div>
  361. <?php endif; ?>
  362. <?php
  363. }
  364. /**
  365. * Outputs a comment in the HTML5 format.
  366. *
  367. * @since 3.6.0
  368. *
  369. * @see wp_list_comments()
  370. *
  371. * @param WP_Comment $comment Comment to display.
  372. * @param int $depth Depth of the current comment.
  373. * @param array $args An array of arguments.
  374. */
  375. protected function html5_comment( $comment, $depth, $args ) {
  376. $tag = ( 'div' === $args['style'] ) ? 'div' : 'li';
  377. $commenter = wp_get_current_commenter();
  378. $show_pending_links = ! empty( $commenter['comment_author'] );
  379. if ( $commenter['comment_author_email'] ) {
  380. $moderation_note = __( 'Your comment is awaiting moderation.' );
  381. } else {
  382. $moderation_note = __( 'Your comment is awaiting moderation. This is a preview; your comment will be visible after it has been approved.' );
  383. }
  384. ?>
  385. <<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class( $this->has_children ? 'parent' : '', $comment ); ?>>
  386. <article id="div-comment-<?php comment_ID(); ?>" class="comment-body">
  387. <footer class="comment-meta">
  388. <div class="comment-author vcard">
  389. <?php
  390. if ( 0 != $args['avatar_size'] ) {
  391. echo get_avatar( $comment, $args['avatar_size'] );
  392. }
  393. ?>
  394. <?php
  395. $comment_author = get_comment_author_link( $comment );
  396. if ( '0' == $comment->comment_approved && ! $show_pending_links ) {
  397. $comment_author = get_comment_author( $comment );
  398. }
  399. printf(
  400. /* translators: %s: Comment author link. */
  401. __( '%s <span class="says">says:</span>' ),
  402. sprintf( '<b class="fn">%s</b>', $comment_author )
  403. );
  404. ?>
  405. </div><!-- .comment-author -->
  406. <div class="comment-metadata">
  407. <?php
  408. printf(
  409. '<a href="%s"><time datetime="%s">%s</time></a>',
  410. esc_url( get_comment_link( $comment, $args ) ),
  411. get_comment_time( 'c' ),
  412. sprintf(
  413. /* translators: 1: Comment date, 2: Comment time. */
  414. __( '%1$s at %2$s' ),
  415. get_comment_date( '', $comment ),
  416. get_comment_time()
  417. )
  418. );
  419. edit_comment_link( __( 'Edit' ), ' <span class="edit-link">', '</span>' );
  420. ?>
  421. </div><!-- .comment-metadata -->
  422. <?php if ( '0' == $comment->comment_approved ) : ?>
  423. <em class="comment-awaiting-moderation"><?php echo $moderation_note; ?></em>
  424. <?php endif; ?>
  425. </footer><!-- .comment-meta -->
  426. <div class="comment-content">
  427. <?php comment_text(); ?>
  428. </div><!-- .comment-content -->
  429. <?php
  430. if ( '1' == $comment->comment_approved || $show_pending_links ) {
  431. comment_reply_link(
  432. array_merge(
  433. $args,
  434. array(
  435. 'add_below' => 'div-comment',
  436. 'depth' => $depth,
  437. 'max_depth' => $args['max_depth'],
  438. 'before' => '<div class="reply">',
  439. 'after' => '</div>',
  440. )
  441. )
  442. );
  443. }
  444. ?>
  445. </article><!-- .comment-body -->
  446. <?php
  447. }
  448. }