class-wp-comments-list-table.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. <?php
  2. /**
  3. * List Table API: WP_Comments_List_Table class
  4. *
  5. * @package WordPress
  6. * @subpackage Administration
  7. * @since 3.1.0
  8. */
  9. /**
  10. * Core class used to implement displaying comments in a list table.
  11. *
  12. * @since 3.1.0
  13. * @access private
  14. *
  15. * @see WP_List_Table
  16. */
  17. class WP_Comments_List_Table extends WP_List_Table {
  18. public $checkbox = true;
  19. public $pending_count = array();
  20. public $extra_items;
  21. private $user_can;
  22. /**
  23. * Constructor.
  24. *
  25. * @since 3.1.0
  26. *
  27. * @see WP_List_Table::__construct() for more information on default arguments.
  28. *
  29. * @global int $post_id
  30. *
  31. * @param array $args An associative array of arguments.
  32. */
  33. public function __construct( $args = array() ) {
  34. global $post_id;
  35. $post_id = isset( $_REQUEST['p'] ) ? absint( $_REQUEST['p'] ) : 0;
  36. if ( get_option( 'show_avatars' ) ) {
  37. add_filter( 'comment_author', array( $this, 'floated_admin_avatar' ), 10, 2 );
  38. }
  39. parent::__construct( array(
  40. 'plural' => 'comments',
  41. 'singular' => 'comment',
  42. 'ajax' => true,
  43. 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
  44. ) );
  45. }
  46. public function floated_admin_avatar( $name, $comment_ID ) {
  47. $comment = get_comment( $comment_ID );
  48. $avatar = get_avatar( $comment, 32, 'mystery' );
  49. return "$avatar $name";
  50. }
  51. /**
  52. * @return bool
  53. */
  54. public function ajax_user_can() {
  55. return current_user_can('edit_posts');
  56. }
  57. /**
  58. *
  59. * @global int $post_id
  60. * @global string $comment_status
  61. * @global string $search
  62. * @global string $comment_type
  63. */
  64. public function prepare_items() {
  65. global $post_id, $comment_status, $search, $comment_type;
  66. $comment_status = isset( $_REQUEST['comment_status'] ) ? $_REQUEST['comment_status'] : 'all';
  67. if ( !in_array( $comment_status, array( 'all', 'moderated', 'approved', 'spam', 'trash' ) ) )
  68. $comment_status = 'all';
  69. $comment_type = !empty( $_REQUEST['comment_type'] ) ? $_REQUEST['comment_type'] : '';
  70. $search = ( isset( $_REQUEST['s'] ) ) ? $_REQUEST['s'] : '';
  71. $post_type = ( isset( $_REQUEST['post_type'] ) ) ? sanitize_key( $_REQUEST['post_type'] ) : '';
  72. $user_id = ( isset( $_REQUEST['user_id'] ) ) ? $_REQUEST['user_id'] : '';
  73. $orderby = ( isset( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : '';
  74. $order = ( isset( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : '';
  75. $comments_per_page = $this->get_per_page( $comment_status );
  76. $doing_ajax = wp_doing_ajax();
  77. if ( isset( $_REQUEST['number'] ) ) {
  78. $number = (int) $_REQUEST['number'];
  79. }
  80. else {
  81. $number = $comments_per_page + min( 8, $comments_per_page ); // Grab a few extra
  82. }
  83. $page = $this->get_pagenum();
  84. if ( isset( $_REQUEST['start'] ) ) {
  85. $start = $_REQUEST['start'];
  86. } else {
  87. $start = ( $page - 1 ) * $comments_per_page;
  88. }
  89. if ( $doing_ajax && isset( $_REQUEST['offset'] ) ) {
  90. $start += $_REQUEST['offset'];
  91. }
  92. $status_map = array(
  93. 'moderated' => 'hold',
  94. 'approved' => 'approve',
  95. 'all' => '',
  96. );
  97. $args = array(
  98. 'status' => isset( $status_map[$comment_status] ) ? $status_map[$comment_status] : $comment_status,
  99. 'search' => $search,
  100. 'user_id' => $user_id,
  101. 'offset' => $start,
  102. 'number' => $number,
  103. 'post_id' => $post_id,
  104. 'type' => $comment_type,
  105. 'orderby' => $orderby,
  106. 'order' => $order,
  107. 'post_type' => $post_type,
  108. );
  109. $_comments = get_comments( $args );
  110. if ( is_array( $_comments ) ) {
  111. update_comment_cache( $_comments );
  112. $this->items = array_slice( $_comments, 0, $comments_per_page );
  113. $this->extra_items = array_slice( $_comments, $comments_per_page );
  114. $_comment_post_ids = array_unique( wp_list_pluck( $_comments, 'comment_post_ID' ) );
  115. $this->pending_count = get_pending_comments_num( $_comment_post_ids );
  116. }
  117. $total_comments = get_comments( array_merge( $args, array(
  118. 'count' => true,
  119. 'offset' => 0,
  120. 'number' => 0
  121. ) ) );
  122. $this->set_pagination_args( array(
  123. 'total_items' => $total_comments,
  124. 'per_page' => $comments_per_page,
  125. ) );
  126. }
  127. /**
  128. *
  129. * @param string $comment_status
  130. * @return int
  131. */
  132. public function get_per_page( $comment_status = 'all' ) {
  133. $comments_per_page = $this->get_items_per_page( 'edit_comments_per_page' );
  134. /**
  135. * Filters the number of comments listed per page in the comments list table.
  136. *
  137. * @since 2.6.0
  138. *
  139. * @param int $comments_per_page The number of comments to list per page.
  140. * @param string $comment_status The comment status name. Default 'All'.
  141. */
  142. return apply_filters( 'comments_per_page', $comments_per_page, $comment_status );
  143. }
  144. /**
  145. *
  146. * @global string $comment_status
  147. */
  148. public function no_items() {
  149. global $comment_status;
  150. if ( 'moderated' === $comment_status ) {
  151. _e( 'No comments awaiting moderation.' );
  152. } else {
  153. _e( 'No comments found.' );
  154. }
  155. }
  156. /**
  157. *
  158. * @global int $post_id
  159. * @global string $comment_status
  160. * @global string $comment_type
  161. */
  162. protected function get_views() {
  163. global $post_id, $comment_status, $comment_type;
  164. $status_links = array();
  165. $num_comments = ( $post_id ) ? wp_count_comments( $post_id ) : wp_count_comments();
  166. $stati = array(
  167. /* translators: %s: all comments count */
  168. 'all' => _nx_noop(
  169. 'All <span class="count">(%s)</span>',
  170. 'All <span class="count">(%s)</span>',
  171. 'comments'
  172. ), // singular not used
  173. /* translators: %s: pending comments count */
  174. 'moderated' => _nx_noop(
  175. 'Pending <span class="count">(%s)</span>',
  176. 'Pending <span class="count">(%s)</span>',
  177. 'comments'
  178. ),
  179. /* translators: %s: approved comments count */
  180. 'approved' => _nx_noop(
  181. 'Approved <span class="count">(%s)</span>',
  182. 'Approved <span class="count">(%s)</span>',
  183. 'comments'
  184. ),
  185. /* translators: %s: spam comments count */
  186. 'spam' => _nx_noop(
  187. 'Spam <span class="count">(%s)</span>',
  188. 'Spam <span class="count">(%s)</span>',
  189. 'comments'
  190. ),
  191. /* translators: %s: trashed comments count */
  192. 'trash' => _nx_noop(
  193. 'Trash <span class="count">(%s)</span>',
  194. 'Trash <span class="count">(%s)</span>',
  195. 'comments'
  196. )
  197. );
  198. if ( !EMPTY_TRASH_DAYS )
  199. unset($stati['trash']);
  200. $link = admin_url( 'edit-comments.php' );
  201. if ( !empty($comment_type) && 'all' != $comment_type )
  202. $link = add_query_arg( 'comment_type', $comment_type, $link );
  203. foreach ( $stati as $status => $label ) {
  204. $current_link_attributes = '';
  205. if ( $status === $comment_status ) {
  206. $current_link_attributes = ' class="current" aria-current="page"';
  207. }
  208. if ( !isset( $num_comments->$status ) )
  209. $num_comments->$status = 10;
  210. $link = add_query_arg( 'comment_status', $status, $link );
  211. if ( $post_id )
  212. $link = add_query_arg( 'p', absint( $post_id ), $link );
  213. /*
  214. // I toyed with this, but decided against it. Leaving it in here in case anyone thinks it is a good idea. ~ Mark
  215. if ( !empty( $_REQUEST['s'] ) )
  216. $link = add_query_arg( 's', esc_attr( wp_unslash( $_REQUEST['s'] ) ), $link );
  217. */
  218. $status_links[ $status ] = "<a href='$link'$current_link_attributes>" . sprintf(
  219. translate_nooped_plural( $label, $num_comments->$status ),
  220. sprintf( '<span class="%s-count">%s</span>',
  221. ( 'moderated' === $status ) ? 'pending' : $status,
  222. number_format_i18n( $num_comments->$status )
  223. )
  224. ) . '</a>';
  225. }
  226. /**
  227. * Filters the comment status links.
  228. *
  229. * @since 2.5.0
  230. *
  231. * @param array $status_links An array of fully-formed status links. Default 'All'.
  232. * Accepts 'All', 'Pending', 'Approved', 'Spam', and 'Trash'.
  233. */
  234. return apply_filters( 'comment_status_links', $status_links );
  235. }
  236. /**
  237. *
  238. * @global string $comment_status
  239. *
  240. * @return array
  241. */
  242. protected function get_bulk_actions() {
  243. global $comment_status;
  244. $actions = array();
  245. if ( in_array( $comment_status, array( 'all', 'approved' ) ) )
  246. $actions['unapprove'] = __( 'Unapprove' );
  247. if ( in_array( $comment_status, array( 'all', 'moderated' ) ) )
  248. $actions['approve'] = __( 'Approve' );
  249. if ( in_array( $comment_status, array( 'all', 'moderated', 'approved', 'trash' ) ) )
  250. $actions['spam'] = _x( 'Mark as Spam', 'comment' );
  251. if ( 'trash' === $comment_status ) {
  252. $actions['untrash'] = __( 'Restore' );
  253. } elseif ( 'spam' === $comment_status ) {
  254. $actions['unspam'] = _x( 'Not Spam', 'comment' );
  255. }
  256. if ( in_array( $comment_status, array( 'trash', 'spam' ) ) || !EMPTY_TRASH_DAYS )
  257. $actions['delete'] = __( 'Delete Permanently' );
  258. else
  259. $actions['trash'] = __( 'Move to Trash' );
  260. return $actions;
  261. }
  262. /**
  263. *
  264. * @global string $comment_status
  265. * @global string $comment_type
  266. *
  267. * @param string $which
  268. */
  269. protected function extra_tablenav( $which ) {
  270. global $comment_status, $comment_type;
  271. static $has_items;
  272. if ( ! isset( $has_items ) ) {
  273. $has_items = $this->has_items();
  274. }
  275. ?>
  276. <div class="alignleft actions">
  277. <?php
  278. if ( 'top' === $which ) {
  279. ?>
  280. <label class="screen-reader-text" for="filter-by-comment-type"><?php _e( 'Filter by comment type' ); ?></label>
  281. <select id="filter-by-comment-type" name="comment_type">
  282. <option value=""><?php _e( 'All comment types' ); ?></option>
  283. <?php
  284. /**
  285. * Filters the comment types dropdown menu.
  286. *
  287. * @since 2.7.0
  288. *
  289. * @param array $comment_types An array of comment types. Accepts 'Comments', 'Pings'.
  290. */
  291. $comment_types = apply_filters( 'admin_comment_types_dropdown', array(
  292. 'comment' => __( 'Comments' ),
  293. 'pings' => __( 'Pings' ),
  294. ) );
  295. foreach ( $comment_types as $type => $label )
  296. echo "\t" . '<option value="' . esc_attr( $type ) . '"' . selected( $comment_type, $type, false ) . ">$label</option>\n";
  297. ?>
  298. </select>
  299. <?php
  300. /**
  301. * Fires just before the Filter submit button for comment types.
  302. *
  303. * @since 3.5.0
  304. */
  305. do_action( 'restrict_manage_comments' );
  306. submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
  307. }
  308. if ( ( 'spam' === $comment_status || 'trash' === $comment_status ) && current_user_can( 'moderate_comments' ) && $has_items ) {
  309. wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
  310. $title = ( 'spam' === $comment_status ) ? esc_attr__( 'Empty Spam' ) : esc_attr__( 'Empty Trash' );
  311. submit_button( $title, 'apply', 'delete_all', false );
  312. }
  313. /**
  314. * Fires after the Filter submit button for comment types.
  315. *
  316. * @since 2.5.0
  317. *
  318. * @param string $comment_status The comment status name. Default 'All'.
  319. */
  320. do_action( 'manage_comments_nav', $comment_status );
  321. echo '</div>';
  322. }
  323. /**
  324. * @return string|false
  325. */
  326. public function current_action() {
  327. if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
  328. return 'delete_all';
  329. return parent::current_action();
  330. }
  331. /**
  332. *
  333. * @global int $post_id
  334. *
  335. * @return array
  336. */
  337. public function get_columns() {
  338. global $post_id;
  339. $columns = array();
  340. if ( $this->checkbox )
  341. $columns['cb'] = '<input type="checkbox" />';
  342. $columns['author'] = __( 'Author' );
  343. $columns['comment'] = _x( 'Comment', 'column name' );
  344. if ( ! $post_id ) {
  345. /* translators: column name or table row header */
  346. $columns['response'] = __( 'In Response To' );
  347. }
  348. $columns['date'] = _x( 'Submitted On', 'column name' );
  349. return $columns;
  350. }
  351. /**
  352. *
  353. * @return array
  354. */
  355. protected function get_sortable_columns() {
  356. return array(
  357. 'author' => 'comment_author',
  358. 'response' => 'comment_post_ID',
  359. 'date' => 'comment_date'
  360. );
  361. }
  362. /**
  363. * Get the name of the default primary column.
  364. *
  365. * @since 4.3.0
  366. *
  367. * @return string Name of the default primary column, in this case, 'comment'.
  368. */
  369. protected function get_default_primary_column_name() {
  370. return 'comment';
  371. }
  372. /**
  373. */
  374. public function display() {
  375. wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
  376. $this->display_tablenav( 'top' );
  377. $this->screen->render_screen_reader_content( 'heading_list' );
  378. ?>
  379. <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
  380. <thead>
  381. <tr>
  382. <?php $this->print_column_headers(); ?>
  383. </tr>
  384. </thead>
  385. <tbody id="the-comment-list" data-wp-lists="list:comment">
  386. <?php $this->display_rows_or_placeholder(); ?>
  387. </tbody>
  388. <tbody id="the-extra-comment-list" data-wp-lists="list:comment" style="display: none;">
  389. <?php
  390. $this->items = $this->extra_items;
  391. $this->display_rows_or_placeholder();
  392. ?>
  393. </tbody>
  394. <tfoot>
  395. <tr>
  396. <?php $this->print_column_headers( false ); ?>
  397. </tr>
  398. </tfoot>
  399. </table>
  400. <?php
  401. $this->display_tablenav( 'bottom' );
  402. }
  403. /**
  404. * @global WP_Post $post
  405. * @global WP_Comment $comment
  406. *
  407. * @param WP_Comment $item
  408. */
  409. public function single_row( $item ) {
  410. global $post, $comment;
  411. $comment = $item;
  412. $the_comment_class = wp_get_comment_status( $comment );
  413. if ( ! $the_comment_class ) {
  414. $the_comment_class = '';
  415. }
  416. $the_comment_class = join( ' ', get_comment_class( $the_comment_class, $comment, $comment->comment_post_ID ) );
  417. if ( $comment->comment_post_ID > 0 ) {
  418. $post = get_post( $comment->comment_post_ID );
  419. }
  420. $this->user_can = current_user_can( 'edit_comment', $comment->comment_ID );
  421. echo "<tr id='comment-$comment->comment_ID' class='$the_comment_class'>";
  422. $this->single_row_columns( $comment );
  423. echo "</tr>\n";
  424. unset( $GLOBALS['post'], $GLOBALS['comment'] );
  425. }
  426. /**
  427. * Generate and display row actions links.
  428. *
  429. * @since 4.3.0
  430. *
  431. * @global string $comment_status Status for the current listed comments.
  432. *
  433. * @param WP_Comment $comment The comment object.
  434. * @param string $column_name Current column name.
  435. * @param string $primary Primary column name.
  436. * @return string|void Comment row actions output.
  437. */
  438. protected function handle_row_actions( $comment, $column_name, $primary ) {
  439. global $comment_status;
  440. if ( $primary !== $column_name ) {
  441. return '';
  442. }
  443. if ( ! $this->user_can ) {
  444. return;
  445. }
  446. $the_comment_status = wp_get_comment_status( $comment );
  447. $out = '';
  448. $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
  449. $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
  450. $url = "comment.php?c=$comment->comment_ID";
  451. $approve_url = esc_url( $url . "&action=approvecomment&$approve_nonce" );
  452. $unapprove_url = esc_url( $url . "&action=unapprovecomment&$approve_nonce" );
  453. $spam_url = esc_url( $url . "&action=spamcomment&$del_nonce" );
  454. $unspam_url = esc_url( $url . "&action=unspamcomment&$del_nonce" );
  455. $trash_url = esc_url( $url . "&action=trashcomment&$del_nonce" );
  456. $untrash_url = esc_url( $url . "&action=untrashcomment&$del_nonce" );
  457. $delete_url = esc_url( $url . "&action=deletecomment&$del_nonce" );
  458. // Preorder it: Approve | Reply | Quick Edit | Edit | Spam | Trash.
  459. $actions = array(
  460. 'approve' => '', 'unapprove' => '',
  461. 'reply' => '',
  462. 'quickedit' => '',
  463. 'edit' => '',
  464. 'spam' => '', 'unspam' => '',
  465. 'trash' => '', 'untrash' => '', 'delete' => ''
  466. );
  467. // Not looking at all comments.
  468. if ( $comment_status && 'all' != $comment_status ) {
  469. if ( 'approved' === $the_comment_status ) {
  470. $actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=unapproved' class='vim-u vim-destructive' aria-label='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
  471. } elseif ( 'unapproved' === $the_comment_status ) {
  472. $actions['approve'] = "<a href='$approve_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=approved' class='vim-a vim-destructive' aria-label='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
  473. }
  474. } else {
  475. $actions['approve'] = "<a href='$approve_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved' class='vim-a' aria-label='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
  476. $actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved' class='vim-u' aria-label='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
  477. }
  478. if ( 'spam' !== $the_comment_status ) {
  479. $actions['spam'] = "<a href='$spam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::spam=1' class='vim-s vim-destructive' aria-label='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
  480. } elseif ( 'spam' === $the_comment_status ) {
  481. $actions['unspam'] = "<a href='$unspam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:unspam=1' class='vim-z vim-destructive' aria-label='" . esc_attr__( 'Restore this comment from the spam' ) . "'>" . _x( 'Not Spam', 'comment' ) . '</a>';
  482. }
  483. if ( 'trash' === $the_comment_status ) {
  484. $actions['untrash'] = "<a href='$untrash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:untrash=1' class='vim-z vim-destructive' aria-label='" . esc_attr__( 'Restore this comment from the Trash' ) . "'>" . __( 'Restore' ) . '</a>';
  485. }
  486. if ( 'spam' === $the_comment_status || 'trash' === $the_comment_status || !EMPTY_TRASH_DAYS ) {
  487. $actions['delete'] = "<a href='$delete_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::delete=1' class='delete vim-d vim-destructive' aria-label='" . esc_attr__( 'Delete this comment permanently' ) . "'>" . __( 'Delete Permanently' ) . '</a>';
  488. } else {
  489. $actions['trash'] = "<a href='$trash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' aria-label='" . esc_attr__( 'Move this comment to the Trash' ) . "'>" . _x( 'Trash', 'verb' ) . '</a>';
  490. }
  491. if ( 'spam' !== $the_comment_status && 'trash' !== $the_comment_status ) {
  492. $actions['edit'] = "<a href='comment.php?action=editcomment&amp;c={$comment->comment_ID}' aria-label='" . esc_attr__( 'Edit this comment' ) . "'>". __( 'Edit' ) . '</a>';
  493. $format = '<a data-comment-id="%d" data-post-id="%d" data-action="%s" class="%s" aria-label="%s" href="#">%s</a>';
  494. $actions['quickedit'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'edit', 'vim-q comment-inline', esc_attr__( 'Quick edit this comment inline' ), __( 'Quick&nbsp;Edit' ) );
  495. $actions['reply'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'replyto', 'vim-r comment-inline', esc_attr__( 'Reply to this comment' ), __( 'Reply' ) );
  496. }
  497. /** This filter is documented in wp-admin/includes/dashboard.php */
  498. $actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment );
  499. $i = 0;
  500. $out .= '<div class="row-actions">';
  501. foreach ( $actions as $action => $link ) {
  502. ++$i;
  503. ( ( ( 'approve' === $action || 'unapprove' === $action ) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
  504. // Reply and quickedit need a hide-if-no-js span when not added with ajax
  505. if ( ( 'reply' === $action || 'quickedit' === $action ) && ! wp_doing_ajax() )
  506. $action .= ' hide-if-no-js';
  507. elseif ( ( $action === 'untrash' && $the_comment_status === 'trash' ) || ( $action === 'unspam' && $the_comment_status === 'spam' ) ) {
  508. if ( '1' == get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true ) )
  509. $action .= ' approve';
  510. else
  511. $action .= ' unapprove';
  512. }
  513. $out .= "<span class='$action'>$sep$link</span>";
  514. }
  515. $out .= '</div>';
  516. $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
  517. return $out;
  518. }
  519. /**
  520. *
  521. * @param WP_Comment $comment The comment object.
  522. */
  523. public function column_cb( $comment ) {
  524. if ( $this->user_can ) { ?>
  525. <label class="screen-reader-text" for="cb-select-<?php echo $comment->comment_ID; ?>"><?php _e( 'Select comment' ); ?></label>
  526. <input id="cb-select-<?php echo $comment->comment_ID; ?>" type="checkbox" name="delete_comments[]" value="<?php echo $comment->comment_ID; ?>" />
  527. <?php
  528. }
  529. }
  530. /**
  531. * @param WP_Comment $comment The comment object.
  532. */
  533. public function column_comment( $comment ) {
  534. echo '<div class="comment-author">';
  535. $this->column_author( $comment );
  536. echo '</div>';
  537. if ( $comment->comment_parent ) {
  538. $parent = get_comment( $comment->comment_parent );
  539. if ( $parent ) {
  540. $parent_link = esc_url( get_comment_link( $parent ) );
  541. $name = get_comment_author( $parent );
  542. printf(
  543. /* translators: %s: comment link */
  544. __( 'In reply to %s.' ),
  545. '<a href="' . $parent_link . '">' . $name . '</a>'
  546. );
  547. }
  548. }
  549. comment_text( $comment );
  550. if ( $this->user_can ) { ?>
  551. <div id="inline-<?php echo $comment->comment_ID; ?>" class="hidden">
  552. <textarea class="comment" rows="1" cols="1"><?php
  553. /** This filter is documented in wp-admin/includes/comment.php */
  554. echo esc_textarea( apply_filters( 'comment_edit_pre', $comment->comment_content ) );
  555. ?></textarea>
  556. <div class="author-email"><?php echo esc_attr( $comment->comment_author_email ); ?></div>
  557. <div class="author"><?php echo esc_attr( $comment->comment_author ); ?></div>
  558. <div class="author-url"><?php echo esc_attr( $comment->comment_author_url ); ?></div>
  559. <div class="comment_status"><?php echo $comment->comment_approved; ?></div>
  560. </div>
  561. <?php
  562. }
  563. }
  564. /**
  565. *
  566. * @global string $comment_status
  567. *
  568. * @param WP_Comment $comment The comment object.
  569. */
  570. public function column_author( $comment ) {
  571. global $comment_status;
  572. $author_url = get_comment_author_url( $comment );
  573. $author_url_display = untrailingslashit( preg_replace( '|^http(s)?://(www\.)?|i', '', $author_url ) );
  574. if ( strlen( $author_url_display ) > 50 ) {
  575. $author_url_display = wp_html_excerpt( $author_url_display, 49, '&hellip;' );
  576. }
  577. echo "<strong>"; comment_author( $comment ); echo '</strong><br />';
  578. if ( ! empty( $author_url_display ) ) {
  579. printf( '<a href="%s">%s</a><br />', esc_url( $author_url ), esc_html( $author_url_display ) );
  580. }
  581. if ( $this->user_can ) {
  582. if ( ! empty( $comment->comment_author_email ) ) {
  583. /** This filter is documented in wp-includes/comment-template.php */
  584. $email = apply_filters( 'comment_email', $comment->comment_author_email, $comment );
  585. if ( ! empty( $email ) && '@' !== $email ) {
  586. printf( '<a href="%1$s">%2$s</a><br />', esc_url( 'mailto:' . $email ), esc_html( $email ) );
  587. }
  588. }
  589. $author_ip = get_comment_author_IP( $comment );
  590. if ( $author_ip ) {
  591. $author_ip_url = add_query_arg( array( 's' => $author_ip, 'mode' => 'detail' ), admin_url( 'edit-comments.php' ) );
  592. if ( 'spam' === $comment_status ) {
  593. $author_ip_url = add_query_arg( 'comment_status', 'spam', $author_ip_url );
  594. }
  595. printf( '<a href="%1$s">%2$s</a>', esc_url( $author_ip_url ), esc_html( $author_ip ) );
  596. }
  597. }
  598. }
  599. /**
  600. *
  601. * @param WP_Comment $comment The comment object.
  602. */
  603. public function column_date( $comment ) {
  604. /* translators: 1: comment date, 2: comment time */
  605. $submitted = sprintf( __( '%1$s at %2$s' ),
  606. /* translators: comment date format. See https://secure.php.net/date */
  607. get_comment_date( __( 'Y/m/d' ), $comment ),
  608. get_comment_date( __( 'g:i a' ), $comment )
  609. );
  610. echo '<div class="submitted-on">';
  611. if ( 'approved' === wp_get_comment_status( $comment ) && ! empty ( $comment->comment_post_ID ) ) {
  612. printf(
  613. '<a href="%s">%s</a>',
  614. esc_url( get_comment_link( $comment ) ),
  615. $submitted
  616. );
  617. } else {
  618. echo $submitted;
  619. }
  620. echo '</div>';
  621. }
  622. /**
  623. *
  624. * @param WP_Comment $comment The comment object.
  625. */
  626. public function column_response( $comment ) {
  627. $post = get_post();
  628. if ( ! $post ) {
  629. return;
  630. }
  631. if ( isset( $this->pending_count[$post->ID] ) ) {
  632. $pending_comments = $this->pending_count[$post->ID];
  633. } else {
  634. $_pending_count_temp = get_pending_comments_num( array( $post->ID ) );
  635. $pending_comments = $this->pending_count[$post->ID] = $_pending_count_temp[$post->ID];
  636. }
  637. if ( current_user_can( 'edit_post', $post->ID ) ) {
  638. $post_link = "<a href='" . get_edit_post_link( $post->ID ) . "' class='comments-edit-item-link'>";
  639. $post_link .= esc_html( get_the_title( $post->ID ) ) . '</a>';
  640. } else {
  641. $post_link = esc_html( get_the_title( $post->ID ) );
  642. }
  643. echo '<div class="response-links">';
  644. if ( 'attachment' === $post->post_type && ( $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ) ) ) {
  645. echo $thumb;
  646. }
  647. echo $post_link;
  648. $post_type_object = get_post_type_object( $post->post_type );
  649. echo "<a href='" . get_permalink( $post->ID ) . "' class='comments-view-item-link'>" . $post_type_object->labels->view_item . '</a>';
  650. echo '<span class="post-com-count-wrapper post-com-count-', $post->ID, '">';
  651. $this->comments_bubble( $post->ID, $pending_comments );
  652. echo '</span> ';
  653. echo '</div>';
  654. }
  655. /**
  656. *
  657. * @param WP_Comment $comment The comment object.
  658. * @param string $column_name The custom column's name.
  659. */
  660. public function column_default( $comment, $column_name ) {
  661. /**
  662. * Fires when the default column output is displayed for a single row.
  663. *
  664. * @since 2.8.0
  665. *
  666. * @param string $column_name The custom column's name.
  667. * @param int $comment->comment_ID The custom column's unique ID number.
  668. */
  669. do_action( 'manage_comments_custom_column', $column_name, $comment->comment_ID );
  670. }
  671. }