PluginProbe
bbPress / 2.6.17
bbPress v2.6.17
2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 2.2 2.2.1 All 72 releases
bbpress / includes / admin / replies.php

replies.php in bbPress 2.6.17, at includes/admin/replies.php

1,125 lines 36.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * bbPress Replies Admin Class
5 *
6 * @package bbPress
7 * @subpackage Administration
8 */
9
10 // Exit if accessed directly
11 defined( 'ABSPATH' ) || exit;
12
13 if ( ! class_exists( 'BBP_Replies_Admin' ) ) :
14 /**
15 * Loads bbPress replies admin area
16 *
17 * @package bbPress
18 * @subpackage Administration
19 * @since 2.0.0 bbPress (r2464)
20 */
21 class BBP_Replies_Admin {
22
23 /** Variables *************************************************************/
24
25 /**
26 * @var The post type of this admin component
27 */
28 private $post_type = '';
29
30 /** Functions *************************************************************/
31
32 /**
33 * The main bbPress admin loader
34 *
35 * @since 2.0.0 bbPress (r2515)
36 */
37 public function __construct() {
38 $this->setup_globals();
39 $this->setup_actions();
40 }
41
42 /**
43 * Setup the admin hooks, actions and filters
44 *
45 * @since 2.0.0 bbPress (r2646)
46 * @since 2.6.0 bbPress (r6101) Added bulk actions
47 *
48 * @access private
49 */
50 private function setup_actions() {
51
52 // Messages
53 add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
54
55 // Reply bulk actions, added in WordPress 4.7, see #WP16031
56 if ( bbp_get_major_wp_version() >= 4.7 ) {
57 add_filter( 'bulk_actions-edit-reply', array( $this, 'bulk_actions' ) );
58 add_filter( 'handle_bulk_actions-edit-reply', array( $this, 'handle_bulk_actions' ), 10, 3 );
59 add_filter( 'bulk_post_updated_messages', array( $this, 'bulk_post_updated_messages' ), 10, 2 );
60 }
61
62 // Reply column headers.
63 add_filter( 'manage_' . $this->post_type . '_posts_columns', array( $this, 'column_headers' ) );
64
65 // Reply columns (in post row)
66 add_action( 'manage_' . $this->post_type . '_posts_custom_column', array( $this, 'column_data' ), 10, 2 );
67 add_filter( 'post_row_actions', array( $this, 'row_actions' ), 10, 2 );
68
69 // Reply meta-box actions
70 add_action( 'add_meta_boxes', array( $this, 'attributes_metabox' ) );
71 add_action( 'add_meta_boxes', array( $this, 'author_metabox' ) );
72 add_action( 'add_meta_boxes', array( $this, 'comments_metabox' ) );
73 add_action( 'save_post', array( $this, 'save_meta_boxes' ) );
74
75 // Check if there are any bbp_toggle_reply_* requests on admin_init, also have a message displayed
76 add_action( 'load-edit.php', array( $this, 'toggle_reply' ) );
77 add_action( 'load-edit.php', array( $this, 'toggle_reply_notice' ) );
78
79 // Add ability to filter topics and replies per forum
80 add_filter( 'restrict_manage_posts', array( $this, 'filter_dropdown' ) );
81 add_filter( 'bbp_request', array( $this, 'filter_post_rows' ) );
82
83 // Empty spam
84 add_filter( 'manage_posts_extra_tablenav', array( $this, 'filter_empty_spam' ) );
85
86 // Contextual Help
87 add_action( 'load-edit.php', array( $this, 'edit_help' ) );
88 add_action( 'load-post.php', array( $this, 'new_help' ) );
89 add_action( 'load-post-new.php', array( $this, 'new_help' ) );
90 }
91
92 /**
93 * Admin globals
94 *
95 * @since 2.0.0 bbPress (r2646)
96 *
97 * @access private
98 */
99 private function setup_globals() {
100 $this->post_type = bbp_get_reply_post_type();
101 }
102
103 /** Contextual Help *******************************************************/
104
105 /**
106 * Contextual help for bbPress reply edit page
107 *
108 * @since 2.0.0 bbPress (r3119)
109 */
110 public function edit_help() {
111
112 // Overview
113 get_current_screen()->add_help_tab(
114 array(
115 'id' => 'overview',
116 'title' => __( 'Overview', 'bbpress' ),
117 'content' =>
118 '<p>' . __( 'This screen provides access to all of your replies. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
119 )
120 );
121
122 // Screen Content
123 get_current_screen()->add_help_tab(
124 array(
125 'id' => 'screen-content',
126 'title' => __( 'Screen Content', 'bbpress' ),
127 'content' =>
128 '<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
129 '<ul>' .
130 '<li>' . __( 'You can hide/display columns based on your needs and decide how many replies to list per screen using the Screen Options tab.', 'bbpress' ) . '</li>' .
131 '<li>' . __( 'You can filter the list of replies by reply status using the text links in the upper left to show All, Published, Draft, Pending, Trashed, or Spam replies. The default view is to show all replies.', 'bbpress' ) . '</li>' .
132 '<li>' . __( 'You can view replies in a simple title list or with an excerpt. Choose the view you prefer by clicking on the icons at the top of the list on the right.', 'bbpress' ) . '</li>' .
133 '<li>' . __( 'You can refine the list to show only replies in a specific forum or from a specific month by using the dropdown menus above the replies list. Click the Filter button after making your selection.', 'bbpress' ) . '</li>' .
134 '</ul>'
135 )
136 );
137
138 // Available Actions
139 get_current_screen()->add_help_tab(
140 array(
141 'id' => 'action-links',
142 'title' => __( 'Available Actions', 'bbpress' ),
143 'content' =>
144 '<p>' . __( 'Hovering over a row in the replies list will display action links that allow you to manage your reply. You can perform the following actions:', 'bbpress' ) . '</p>' .
145 '<ul>' .
146 '<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that reply. You can also reach that screen by clicking on the reply title.', 'bbpress' ) . '</li>' .
147 //'<li>' . __( '<strong>Quick Edit</strong> provides inline access to the metadata of your reply, allowing you to update reply details without leaving this screen.', 'bbpress' ) . '</li>' .
148 '<li>' . __( '<strong>Trash</strong> removes your reply from this list and places it in the trash, from which you can permanently delete it.', 'bbpress' ) . '</li>' .
149 '<li>' . __( '<strong>Spam</strong> removes your reply from this list and places it in the spam queue, from which you can permanently delete it.', 'bbpress' ) . '</li>' .
150 '<li>' . __( '<strong>View</strong> will take you to your live site to view the reply.', 'bbpress' ) . '</li>' .
151 '<li>' . __( '<strong>Approve</strong> will change the status from pending to publish.', 'bbpress' ) . '</li>' .
152 '</ul>'
153 )
154 );
155
156 // Bulk Actions
157 get_current_screen()->add_help_tab(
158 array(
159 'id' => 'bulk-actions',
160 'title' => __( 'Bulk Actions', 'bbpress' ),
161 'content' =>
162 '<p>' . __( 'You can also edit, spam, or move multiple replies to the trash at once. Select the replies you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.', 'bbpress' ) . '</p>' .
163 '<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected replies at once. To remove a reply from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
164 )
165 );
166
167 // Help Sidebar
168 get_current_screen()->set_help_sidebar(
169 '<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
170 '<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>', 'bbpress' ) . '</p>' .
171 '<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
172 );
173 }
174
175 /**
176 * Contextual help for bbPress reply edit page
177 *
178 * @since 2.0.0 bbPress (r3119)
179 */
180 public function new_help() {
181
182 $customize_display = '<p>' . __( 'The title field and the big reply editing Area are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.', 'bbpress' ) . '</p>';
183
184 get_current_screen()->add_help_tab(
185 array(
186 'id' => 'customize-display',
187 'title' => __( 'Customizing This Display', 'bbpress' ),
188 'content' => $customize_display,
189 )
190 );
191
192 get_current_screen()->add_help_tab(
193 array(
194 'id' => 'title-reply-editor',
195 'title' => __( 'Title and Reply Editor', 'bbpress' ),
196 'content' =>
197 '<p>' . __( '<strong>Title</strong> - Enter a title for your reply. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
198 '<p>' . __( '<strong>Reply Editor</strong> - Enter the text for your reply. There are two modes of editing: Visual and HTML. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The HTML mode allows you to enter raw HTML along with your reply text. You can insert media files by clicking the icons above the reply editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in HTML mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular reply editor.', 'bbpress' ) . '</p>'
199 )
200 );
201
202 $publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your reply in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a reply or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a reply to be published in the future or backdate a reply.', 'bbpress' ) . '</p>';
203
204 if ( current_theme_supports( 'reply-thumbnails' ) && post_type_supports( bbp_get_reply_post_type(), 'thumbnail' ) ) {
205 $publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your reply without inserting it. This is usually useful only if your theme makes use of the featured image as a reply thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
206 }
207
208 get_current_screen()->add_help_tab(
209 array(
210 'id' => 'reply-attributes',
211 'title' => __( 'Reply Attributes', 'bbpress' ),
212 'content' =>
213 '<p>' . __( 'Select the attributes that your reply should have:', 'bbpress' ) . '</p>' .
214 '<ul>' .
215 '<li>' . __( '<strong>Forum</strong> dropdown determines the parent forum that the reply belongs to. Select the forum, or leave the default (Use Forum of Topic) to post the reply in forum of the topic.', 'bbpress' ) . '</li>' .
216 '<li>' . __( '<strong>Topic</strong> determines the parent topic that the reply belongs to.', 'bbpress' ) . '</li>' .
217 '<li>' . __( '<strong>Reply To</strong> determines the threading of the reply.', 'bbpress' ) . '</li>' .
218 '</ul>'
219 )
220 );
221
222 get_current_screen()->add_help_tab(
223 array(
224 'id' => 'publish-box',
225 'title' => __( 'Publish Box', 'bbpress' ),
226 'content' => $publish_box,
227 )
228 );
229
230 get_current_screen()->set_help_sidebar(
231 '<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
232 '<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>', 'bbpress' ) . '</p>' .
233 '<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
234 );
235 }
236
237 /**
238 * Add spam/unspam bulk actions to the bulk action dropdown.
239 *
240 * @since 2.6.0 bbPress (r6101)
241 *
242 * @param array $actions The list of bulk actions.
243 * @return array The filtered list of bulk actions.
244 */
245 public function bulk_actions( $actions ) {
246
247 if ( current_user_can( 'moderate' ) ) {
248 if ( bbp_get_spam_status_id() === get_query_var( 'post_status' ) ) {
249 $actions['unspam'] = esc_html__( 'Unspam', 'bbpress' );
250 } else {
251 $actions['spam'] = esc_html__( 'Spam', 'bbpress' );
252 }
253 }
254
255 return $actions;
256 }
257
258 /**
259 * Add custom bulk action updated messages for replies.
260 *
261 * @since 2.6.0 bbPress (r6101)
262 *
263 * @param array $bulk_messages Arrays of messages, each keyed by the corresponding post type.
264 * @param array $bulk_counts Array of item counts for each message, used to build internationalized strings.
265 */
266 public function bulk_post_updated_messages( $bulk_messages, $bulk_counts ) {
267 /* translators: %s: Number of replies */
268 $bulk_messages['reply']['updated'] = _n( '%s reply updated.', '%s replies updated.', $bulk_counts['updated'], 'bbpress');
269 $bulk_messages['reply']['locked'] = ( 1 === $bulk_counts['locked'] )
270 ? __( '1 reply not updated, somebody is editing it.', 'bbpress' )
271 /* translators: %s: Number of replies */
272 : _n( '%s reply not updated, somebody is editing it.', '%s replies not updated, somebody is editing them.', $bulk_counts['locked'], 'bbpress' );
273
274 return $bulk_messages;
275 }
276
277 /**
278 * Handle spam/unspam bulk actions.
279 *
280 * @since 2.6.0 bbPress (r6101)
281 *
282 * @param string $sendback The sendback URL.
283 * @param string $doaction The action to be taken.
284 * @param array $post_ids The post IDS to take the action on.
285 * @return string The sendback URL.
286 */
287 public function handle_bulk_actions( $sendback, $doaction, $post_ids ) {
288
289 $sendback = remove_query_arg( array( 'spam', 'unspam' ), $sendback );
290 $updated = $locked = 0;
291
292 if ( 'spam' === $doaction ) {
293
294 foreach ( (array) $post_ids as $post_id ) {
295 if ( ! current_user_can( 'moderate', $post_id ) ) {
296 wp_die( esc_html__( 'Sorry, you are not allowed to spam this item.', 'bbpress' ) );
297 }
298
299 if ( wp_check_post_lock( $post_id ) ) {
300 $locked++;
301 continue;
302 }
303
304 if ( ! bbp_spam_reply( $post_id ) ) {
305 wp_die( esc_html__( 'Error in spamming reply.', 'bbpress' ) );
306 }
307
308 ++$updated;
309 }
310
311 $sendback = add_query_arg(
312 array(
313 'updated' => $updated,
314 'ids' => implode( ',', $post_ids ),
315 'locked' => $locked
316 ),
317 $sendback
318 );
319
320 } elseif ( 'unspam' === $doaction ) {
321
322 foreach ( (array) $post_ids as $post_id ) {
323 if ( ! current_user_can( 'moderate', $post_id ) ) {
324 wp_die( esc_html__( 'Sorry, you are not allowed to unspam this reply.', 'bbpress' ) );
325 }
326
327 if ( wp_check_post_lock( $post_id ) ) {
328 $locked++;
329 continue;
330 }
331
332 if ( ! bbp_unspam_reply( $post_id ) ) {
333 wp_die( esc_html__( 'Error in unspamming reply.', 'bbpress' ) );
334 }
335
336 ++$updated;
337 }
338
339 $sendback = add_query_arg(
340 array(
341 'updated' => $updated,
342 'ids' => implode( ',', $post_ids ),
343 'locked' => $locked
344 ),
345 $sendback
346 );
347 }
348
349 return $sendback;
350 }
351
352 /**
353 * Add the reply attributes meta-box
354 *
355 * @since 2.0.0 bbPress (r2746)
356 */
357 public function attributes_metabox() {
358 add_meta_box(
359 'bbp_reply_attributes',
360 esc_html__( 'Reply Attributes', 'bbpress' ),
361 'bbp_reply_metabox',
362 $this->post_type,
363 'side',
364 'high'
365 );
366 }
367
368 /**
369 * Add the author info meta-box
370 *
371 * Allows editing of information about an author
372 *
373 * @since 2.0.0 bbPress (r2828)
374 */
375 public function author_metabox() {
376
377 // Bail if post_type is not a reply
378 if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
379 return;
380 }
381
382 // Add the meta-box
383 add_meta_box(
384 'bbp_author_metabox',
385 esc_html__( 'Author Information', 'bbpress' ),
386 'bbp_author_metabox',
387 $this->post_type,
388 'side',
389 'high'
390 );
391 }
392
393 /**
394 * Remove comments & discussion meta-boxes if comments are not supported
395 *
396 * @since 2.6.0 bbPress (r6186)
397 */
398 public function comments_metabox() {
399 if ( ! post_type_supports( $this->post_type, 'comments' ) ) {
400 remove_meta_box( 'commentstatusdiv', $this->post_type, 'normal' );
401 remove_meta_box( 'commentsdiv', $this->post_type, 'normal' );
402 }
403 }
404
405 /**
406 * Pass the reply attributes for processing
407 *
408 * @since 2.0.0 bbPress (r2746)
409 *
410 * @param int $reply_id Reply id
411 * @return int Parent id
412 */
413 public function save_meta_boxes( $reply_id ) {
414
415 // Bail if doing an autosave
416 if ( bbp_doing_autosave() ) {
417 return $reply_id;
418 }
419
420 // Bail if not a post request
421 if ( ! bbp_is_post_request() ) {
422 return $reply_id;
423 }
424
425 // Check action exists
426 if ( empty( $_POST['action'] ) ) {
427 return $reply_id;
428 }
429
430 // Nonce check
431 if ( empty( $_POST['bbp_reply_metabox'] ) || ! wp_verify_nonce( $_POST['bbp_reply_metabox'], 'bbp_reply_metabox_save' ) ) {
432 return $reply_id;
433 }
434
435 // Bail if current user cannot edit this reply
436 if ( ! current_user_can( 'edit_reply', $reply_id ) ) {
437 return $reply_id;
438 }
439
440 // Get the reply meta post values
441 $topic_id = ! empty( $_POST['parent_id'] ) ? (int) $_POST['parent_id'] : 0;
442 $forum_id = ! empty( $_POST['bbp_forum_id'] ) ? (int) $_POST['bbp_forum_id'] : bbp_get_topic_forum_id( $topic_id );
443 $reply_to = ! empty( $_POST['bbp_reply_to'] ) ? (int) $_POST['bbp_reply_to'] : 0;
444
445 // Get reply author data
446 $anonymous_data = bbp_filter_anonymous_post_data();
447 $author_id = bbp_get_reply_author_id( $reply_id );
448 $is_edit = ( isset( $_POST['hidden_post_status'] ) && ( 'draft' !== $_POST['hidden_post_status'] ) );
449
450 // Formally update the reply
451 bbp_update_reply( $reply_id, $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit, $reply_to );
452
453 // Allow other fun things to happen
454 do_action( 'bbp_reply_attributes_metabox_save', $reply_id, $topic_id, $forum_id, $reply_to );
455 do_action( 'bbp_author_metabox_save', $reply_id, $anonymous_data );
456
457 return $reply_id;
458 }
459
460 /**
461 * Toggle reply
462 *
463 * Handles the admin-side spamming/unspamming of replies
464 *
465 * @since 2.0.0 bbPress (r2740)
466 */
467 public function toggle_reply() {
468
469 // Bail if not a topic toggle action
470 if ( ! bbp_is_get_request() || empty( $_GET['action'] ) || empty( $_GET['reply_id'] ) ) {
471 return;
472 }
473
474 // Bail if not an allowed action
475 $action = sanitize_key( $_GET['action'] );
476 if ( empty( $action ) || ! in_array( $action, $this->get_allowed_action_toggles(), true ) ) {
477 return;
478 }
479
480 // Get reply and die if empty
481 $reply_id = bbp_get_reply_id( $_GET['reply_id'] );
482 if ( ! bbp_get_reply( $reply_id ) ) {
483 wp_die( esc_html__( 'The reply was not found.', 'bbpress' ) );
484 }
485
486 // What is the user doing here?
487 if ( ! current_user_can( 'moderate', $reply_id ) ) {
488 wp_die( esc_html__( 'You do not have permission to do that.', 'bbpress' ) );
489 }
490
491 // Defaults
492 $post_data = array( 'ID' => $reply_id );
493 $message = '';
494 $success = false;
495
496 switch ( $action ) {
497 case 'bbp_toggle_reply_approve' :
498 check_admin_referer( 'approve-reply_' . $reply_id );
499
500 $is_approve = bbp_is_reply_public( $reply_id );
501 $message = ( true === $is_approve )
502 ? 'unpproved'
503 : 'approved';
504 $success = ( true === $is_approve )
505 ? bbp_unapprove_reply( $reply_id )
506 : bbp_approve_reply( $reply_id );
507
508 break;
509
510 case 'bbp_toggle_reply_spam' :
511 check_admin_referer( 'spam-reply_' . $reply_id );
512
513 $is_spam = bbp_is_reply_spam( $reply_id );
514 $message = ( true === $is_spam )
515 ? 'unspammed'
516 : 'spammed';
517 $success = ( true === $is_spam )
518 ? bbp_unspam_reply( $reply_id )
519 : bbp_spam_reply( $reply_id );
520
521 break;
522 }
523
524 // Setup the message
525 $retval = array(
526 'bbp_reply_toggle_notice' => $message,
527 'reply_id' => $reply_id
528 );
529
530 // Prepare for failure
531 if ( ( false === $success ) || is_wp_error( $success ) ) {
532 $retval['failed'] = '1';
533 }
534
535 // Filter all message args
536 $retval = apply_filters( 'bbp_toggle_reply_action_admin', $retval, $reply_id, $action );
537
538 // Do additional reply toggle actions (admin side)
539 do_action( 'bbp_toggle_reply_admin', $success, $post_data, $action, $retval );
540
541 // Redirect back to the reply
542 $redirect = add_query_arg( $retval, remove_query_arg( array( 'action', 'reply_id' ) ) );
543 bbp_redirect( $redirect );
544 }
545
546 /**
547 * Toggle reply notices
548 *
549 * Display the success/error notices from
550 * {@link BBP_Admin::toggle_reply()}
551 *
552 * @since 2.0.0 bbPress (r2740)
553 */
554 public function toggle_reply_notice() {
555
556 // Bail if missing reply toggle action
557 if ( ! bbp_is_get_request() || empty( $_GET['reply_id'] ) || empty( $_GET['bbp_reply_toggle_notice'] ) ) {
558 return;
559 }
560
561 // Bail if not an allowed notice
562 $notice = sanitize_key( $_GET['bbp_reply_toggle_notice'] );
563 if ( empty( $notice ) || ! in_array( $notice, $this->get_allowed_notice_toggles(), true ) ) {
564 return;
565 }
566
567 // Bail if no reply_id or notice
568 $reply_id = bbp_get_reply_id( $_GET['reply_id'] );
569 if ( empty( $reply_id ) ) {
570 return;
571 }
572
573 // Bail if reply is missing
574 if ( ! bbp_get_reply( $reply_id ) ) {
575 return;
576 }
577
578 // Use the title in the responses
579 $reply_title = bbp_get_reply_title( $reply_id );
580 $is_failure = ! empty( $_GET['failed'] );
581 $message = '';
582
583 switch ( $notice ) {
584 case 'spammed' :
585 $message = ( true === $is_failure )
586 /* translators: %s: Reply title */
587 ? sprintf( esc_html__( 'There was a problem marking the reply "%1$s" as spam.', 'bbpress' ), $reply_title )
588 /* translators: %s: Reply title */
589 : sprintf( esc_html__( 'Reply "%1$s" successfully marked as spam.', 'bbpress' ), $reply_title );
590 break;
591
592 case 'unspammed' :
593 $message = ( true === $is_failure )
594 /* translators: %s: Reply title */
595 ? sprintf( esc_html__( 'There was a problem unmarking the reply "%1$s" as spam.', 'bbpress' ), $reply_title )
596 /* translators: %s: Reply title */
597 : sprintf( esc_html__( 'Reply "%1$s" successfully unmarked as spam.', 'bbpress' ), $reply_title );
598 break;
599
600 case 'approved' :
601 $message = ( true === $is_failure )
602 /* translators: %s: Reply title */
603 ? sprintf( esc_html__( 'There was a problem approving the reply "%1$s".', 'bbpress' ), $reply_title )
604 /* translators: %s: Reply title */
605 : sprintf( esc_html__( 'Reply "%1$s" successfully approved.', 'bbpress' ), $reply_title );
606 break;
607
608 case 'unapproved' :
609 $message = ( true === $is_failure )
610 /* translators: %s: Reply title */
611 ? sprintf( esc_html__( 'There was a problem unapproving the reply "%1$s".', 'bbpress' ), $reply_title )
612 /* translators: %s: Reply title */
613 : sprintf( esc_html__( 'Reply "%1$s" successfully unapproved.', 'bbpress' ), $reply_title );
614 break;
615 }
616
617 // Do additional reply toggle notice filters (admin side)
618 $message = apply_filters( 'bbp_toggle_reply_notice_admin', $message, $reply_id, $notice, $is_failure );
619 $class = ( true === $is_failure )
620 ? 'error'
621 : 'updated';
622
623 // Add the notice
624 bbp_admin()->add_notice( $message, $class, true );
625 }
626
627 /**
628 * Returns an array of keys used to sort row actions
629 *
630 * @since 2.6.0 bbPress (r6771)
631 *
632 * @return array
633 */
634 private function get_row_action_sort_order() {
635
636 /**
637 * Filters the row action sort order for replies.
638 *
639 * @since 2.6.0 bbPress (r6771)
640 *
641 * @param array $order The default sort order.
642 */
643 return (array) apply_filters(
644 'bbp_admin_reply_row_action_sort_order',
645 array(
646 'edit',
647 'approved',
648 'unapproved',
649 'spam',
650 'unspam',
651 'trash',
652 'untrash',
653 'delete',
654 'view'
655 )
656 );
657 }
658
659 /**
660 * Returns an array of notice toggles
661 *
662 * @since 2.6.0 bbPress (r6396)
663 *
664 * @return array
665 */
666 private function get_allowed_notice_toggles() {
667
668 // Filter & return
669 return apply_filters(
670 'bbp_admin_replies_allowed_notice_toggles',
671 array(
672 'spammed',
673 'unspammed',
674 'approved',
675 'unapproved'
676 )
677 );
678 }
679
680 /**
681 * Returns an array of notice toggles
682 *
683 * @since 2.6.0 bbPress (r6396)
684 *
685 * @return array
686 */
687 private function get_allowed_action_toggles() {
688
689 // Filter & return
690 return apply_filters(
691 'bbp_admin_replies_allowed_action_toggles',
692 array(
693 'bbp_toggle_reply_spam',
694 'bbp_toggle_reply_approve'
695 )
696 );
697 }
698
699 /**
700 * Manage the column headers for the replies page
701 *
702 * @since 2.0.0 bbPress (r2577)
703 *
704 * @param array $columns The columns
705 *
706 * @return array $columns bbPress reply columns
707 */
708 public function column_headers( $columns ) {
709 $columns = array(
710 'cb' => '<input type="checkbox" />',
711 'title' => esc_html__( 'Title', 'bbpress' ),
712 'bbp_reply_forum' => esc_html__( 'Forum', 'bbpress' ),
713 'bbp_reply_topic' => esc_html__( 'Topic', 'bbpress' ),
714 'bbp_reply_author' => esc_html__( 'Author', 'bbpress' ),
715 'bbp_reply_created' => esc_html__( 'Created', 'bbpress' ),
716 );
717
718 // Filter & return
719 return apply_filters( 'bbp_admin_replies_column_headers', $columns );
720 }
721
722 /**
723 * Print extra columns for the replies page
724 *
725 * @since 2.0.0 bbPress (r2577)
726 *
727 * @param string $column Column
728 * @param int $reply_id reply id
729 */
730 public function column_data( $column, $reply_id ) {
731
732 // Get topic ID
733 $topic_id = bbp_get_reply_topic_id( $reply_id );
734
735 // Populate Column Data
736 switch ( $column ) {
737
738 // Topic
739 case 'bbp_reply_topic' :
740
741 // Get title
742 $topic_title = ! empty( $topic_id )
743 ? bbp_get_topic_title( $topic_id )
744 : '';
745
746 // Output topic name
747 if ( ! empty( $topic_title ) ) {
748 echo $topic_title;
749
750 // Output dash
751 } else {
752 ?>
753 <span aria-hidden="true">&mdash;</span>
754 <span class="screen-reader-text"><?php esc_html_e( 'No topic', 'bbpress' ); ?></span>
755 <?php
756 }
757
758 break;
759
760 // Forum
761 case 'bbp_reply_forum' :
762
763 // Get Forum ID's
764 $reply_forum_id = bbp_get_reply_forum_id( $reply_id );
765 $topic_forum_id = bbp_get_topic_forum_id( $topic_id );
766
767 // Forum Title
768 $forum_title = ! empty( $reply_forum_id )
769 ? bbp_get_forum_title( $reply_forum_id )
770 : '';
771
772 // Alert capable users of reply forum mismatch
773 if ( $reply_forum_id !== $topic_forum_id ) {
774 if ( current_user_can( 'edit_others_replies' ) || current_user_can( 'moderate', $reply_id ) ) {
775 $forum_title .= '<div class="attention">' . esc_html__( '(Mismatch)', 'bbpress' ) . '</div>';
776 }
777 }
778
779 // Output forum name
780 if ( ! empty( $forum_title ) ) {
781 echo $forum_title;
782
783 // Reply has no forum
784 } else {
785 ?>
786 <span aria-hidden="true">&mdash;</span>
787 <span class="screen-reader-text"><?php esc_html_e( 'No forum', 'bbpress' ); ?></span>
788 <?php
789 }
790
791 break;
792
793 // Author
794 case 'bbp_reply_author' :
795 bbp_reply_author_display_name( $reply_id );
796 break;
797
798 // Freshness
799 case 'bbp_reply_created':
800
801 // Output last activity time and date
802 printf( '%1$s <br /> %2$s',
803 get_the_date(),
804 esc_attr( get_the_time() )
805 );
806
807 break;
808
809 // Do action for anything else
810 default :
811 do_action( 'bbp_admin_replies_column_data', $column, $reply_id );
812 break;
813 }
814 }
815
816 /**
817 * Reply Row actions
818 *
819 * Remove the quick-edit action link under the reply title and add the
820 * content and spam link
821 *
822 * @since 2.0.0 bbPress (r2577)
823 *
824 * @param array $actions Actions
825 * @param object $reply Reply object
826 *
827 * @return array $actions Actions
828 */
829 public function row_actions( $actions = array(), $reply = false ) {
830
831 // Disable quick edit (too much to do here)
832 unset( $actions['inline hide-if-no-js'] );
833
834 // View link
835 $view_link = bbp_get_reply_url( $reply->ID );
836
837 // Maybe add view=all
838 if ( ! in_array( $reply->post_status, array( bbp_get_closed_status_id(), bbp_get_public_status_id() ), true ) ) {
839 $view_link = bbp_add_view_all( $view_link, true );
840 }
841
842 // Reply view links to topic
843 $view_title = sprintf(
844 /* translators: %s: Reply title */
845 __( 'View &#8220;%s&#8221;', 'bbpress' ),
846 bbp_get_reply_title( $reply->ID )
847 );
848
849 $actions['view'] = sprintf(
850 '<a href="%1$s" title="%2$s" rel="permalink">%3$s</a>',
851 esc_url( $view_link ),
852 esc_attr( $view_title ),
853 esc_html__( 'View', 'bbpress' )
854 );
855
856 // User cannot view replies in trash
857 if ( ( bbp_get_trash_status_id() === $reply->post_status ) && ! current_user_can( 'view_trash' ) ) {
858 unset( $actions['view'] );
859 }
860
861 // Only show the actions if the user is capable of viewing them
862 if ( current_user_can( 'moderate', $reply->ID ) ) {
863
864 // Show the 'approve' link on non-published posts only and 'unapprove' on published posts only
865 $args = array(
866 'reply_id' => $reply->ID,
867 'action' => 'bbp_toggle_reply_approve'
868 );
869 $approve_uri = wp_nonce_url( add_query_arg( $args, remove_query_arg( array( 'bbp_reply_toggle_notice', 'reply_id', 'failed', 'super' ) ) ), 'approve-reply_' . $reply->ID );
870 if ( bbp_is_reply_public( $reply->ID ) ) {
871 $actions['unapproved'] = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Unapprove this reply', 'bbpress' ) . '">' . _x( 'Unapprove', 'Unapprove reply', 'bbpress' ) . '</a>';
872 } else {
873 $actions['approved'] = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Approve this reply', 'bbpress' ) . '">' . _x( 'Approve', 'Approve reply', 'bbpress' ) . '</a>';
874 }
875
876 // Show the 'spam' link on published and pending replies and 'not spam' on spammed replies
877 if ( in_array( $reply->post_status, array( bbp_get_public_status_id(), bbp_get_trash_status_id(), bbp_get_pending_status_id(), bbp_get_spam_status_id() ), true ) ) {
878 $args = array(
879 'reply_id' => $reply->ID,
880 'action' => 'bbp_toggle_reply_spam'
881 );
882 $spam_uri = wp_nonce_url( add_query_arg( $args, remove_query_arg( array( 'bbp_reply_toggle_notice', 'reply_id', 'failed', 'super' ) ) ), 'spam-reply_' . $reply->ID );
883 if ( ! bbp_is_reply_spam( $reply->ID ) ) {
884 $actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark this reply as spam', 'bbpress' ) . '">' . esc_html__( 'Spam', 'bbpress' ) . '</a>';
885 } else {
886 $actions['unspam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark the reply as not spam', 'bbpress' ) . '">' . esc_html__( 'Not Spam', 'bbpress' ) . '</a>';
887 }
888 }
889 }
890
891 // Trash
892 if ( current_user_can( 'delete_reply', $reply->ID ) ) {
893 $trash_days = bbp_get_trash_days( bbp_get_reply_post_type() );
894
895 if ( bbp_get_trash_status_id() === $reply->post_status ) {
896 $post_type_object = get_post_type_object( bbp_get_reply_post_type() );
897 $actions['untrash'] = "<a title='" . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . "' href='" . esc_url( wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $reply->ID ) ), 'untrash-post_' . $reply->ID ) ) . "'>" . esc_html__( 'Restore', 'bbpress' ) . '</a>';
898 } elseif ( ! empty( $trash_days ) ) {
899 $actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $reply->ID ) ) . "'>" . esc_html__( 'Trash', 'bbpress' ) . '</a>';
900 }
901
902 if ( ( bbp_get_trash_status_id() === $reply->post_status ) || empty( $trash_days ) ) {
903 $actions['delete'] = "<a class='submitdelete' title='" . esc_attr__( 'Delete this item permanently', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $reply->ID, '', true ) ) . "'>" . esc_html__( 'Delete Permanently', 'bbpress' ) . '</a>';
904 }
905 }
906
907 // Sort & return
908 return $this->sort_row_actions( $actions );
909 }
910
911 /**
912 * Sort row actions by key
913 *
914 * @since 2.6.0
915 *
916 * @param array $actions
917 *
918 * @return array
919 */
920 private function sort_row_actions( $actions = array() ) {
921
922 // Return value
923 $retval = array();
924
925 // Known row actions, in sort order
926 $known_actions = $this->get_row_action_sort_order();
927
928 // Sort known actions, and keep any unknown ones
929 foreach ( $known_actions as $key ) {
930 if ( isset( $actions[ $key ] ) ) {
931 $retval[ $key ] = $actions[ $key ];
932 unset( $actions[ $key ] );
933 }
934 }
935
936 // Combine & return
937 return $retval + $actions;
938 }
939
940 /**
941 * Add forum dropdown to topic and reply list table filters
942 *
943 * @since 2.0.0 bbPress (r2991)
944 *
945 * @return bool False. If post type is not topic or reply
946 */
947 public function filter_dropdown() {
948
949 // Get which forum is selected
950 $selected = ! empty( $_GET['bbp_forum_id'] )
951 ? (int) $_GET['bbp_forum_id']
952 : 0;
953
954 // Show the forums dropdown
955 bbp_dropdown(
956 array(
957 'selected' => $selected,
958 'show_none' => esc_html__( 'In all forums', 'bbpress' )
959 )
960 );
961 }
962
963 /**
964 * Add "Empty Spam" button for moderators
965 *
966 * @since 2.6.0 bbPress (r6791)
967 */
968 public function filter_empty_spam() {
969
970 // Bail if not viewing spam
971 if ( empty( $_GET['post_status'] ) || ( bbp_get_spam_status_id() !== $_GET['post_status'] ) && current_user_can( 'moderate' ) ) {
972 return;
973 }
974
975 ?>
976
977 <div class="alignleft actions"><?php
978
979 // Output the nonce & button
980 wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
981 submit_button(
982 esc_attr__( 'Empty Spam', 'bbpress' ),
983 'button-secondary apply',
984 'delete_all',
985 false
986 );
987
988 ?></div><?php
989 }
990
991 /**
992 * Adjust the request query and include the forum id
993 *
994 * @since 2.0.0 bbPress (r2991)
995 *
996 * @param array $query_vars Query variables from {@link WP_Query}
997 * @return array Processed Query Vars
998 */
999 public function filter_post_rows( $query_vars ) {
1000
1001 // Add post_parent query_var if one is present
1002 if ( ! empty( $_GET['bbp_forum_id'] ) ) {
1003 $query_vars['meta_key'] = '_bbp_forum_id';
1004 $query_vars['meta_type'] = 'NUMERIC';
1005 $query_vars['meta_value'] = (int) $_GET['bbp_forum_id'];
1006 }
1007
1008 // Return manipulated query_vars
1009 return $query_vars;
1010 }
1011
1012 /**
1013 * Custom user feedback messages for reply post type
1014 *
1015 * @since 2.0.0 bbPress (r3080)
1016 *
1017 * @global int $post_ID
1018 *
1019 * @param array $messages
1020 *
1021 * @return array
1022 */
1023 public function updated_messages( $messages ) {
1024 global $post_ID;
1025
1026 // URL for the current topic
1027 $topic_url = bbp_get_topic_permalink( bbp_get_reply_topic_id( $post_ID ) );
1028
1029 // Current reply's post_date
1030 $post_date = bbp_get_global_post_field( 'post_date', 'raw' );
1031
1032 // Messages array
1033 $messages[ $this->post_type ] = array(
1034 0 => '', // Left empty on purpose
1035
1036 // Updated
1037 1 => sprintf(
1038 '%1$s <a href="%2$s">%3$s</a>',
1039 esc_html__( 'Reply updated.', 'bbpress' ),
1040 $topic_url,
1041 esc_html__( 'View topic', 'bbpress' )
1042 ),
1043
1044 // Custom field updated
1045 2 => esc_html__( 'Custom field updated.', 'bbpress' ),
1046
1047 // Custom field deleted
1048 3 => esc_html__( 'Custom field deleted.', 'bbpress' ),
1049
1050 // Reply updated
1051 4 => esc_html__( 'Reply updated.', 'bbpress' ),
1052
1053 // Restored from revision
1054 /* translators: %s: date and time of the revision */
1055 5 => isset( $_GET['revision'] )
1056 /* translators: %s: Date and time of the revision */
1057 ? sprintf( esc_html__( 'Reply restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
1058 : false,
1059
1060 // Reply created
1061 6 => sprintf(
1062 '%1$s <a href="%2$s">%3$s</a>',
1063 esc_html__( 'Reply created.', 'bbpress' ),
1064 $topic_url,
1065 esc_html__( 'View topic', 'bbpress' )
1066 ),
1067
1068 // Reply saved
1069 7 => esc_html__( 'Reply saved.', 'bbpress' ),
1070
1071 // Reply submitted
1072 8 => sprintf(
1073 '%1$s <a href="%2$s" target="_blank">%3$s</a>',
1074 esc_html__( 'Reply submitted.', 'bbpress' ),
1075 esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
1076 esc_html__( 'Preview topic', 'bbpress' )
1077 ),
1078
1079 // Reply scheduled
1080 9 => sprintf(
1081 '%1$s <a target="_blank" href="%2$s">%3$s</a>',
1082 sprintf(
1083 /* translators: Publish box date format, see http://php.net/date */
1084 esc_html__( 'Reply scheduled for: %s.', 'bbpress' ),
1085 '<strong>' . date_i18n( __( 'M j, Y @ G:i', 'bbpress' ), strtotime( $post_date ) ) . '</strong>'
1086 ),
1087 $topic_url,
1088 esc_html__( 'Preview topic', 'bbpress' )
1089 ),
1090
1091 // Reply draft updated
1092 10 => sprintf(
1093 '%1$s <a href="%2$s" target="_blank">%3$s</a>',
1094 esc_html__( 'Reply draft updated.', 'bbpress' ),
1095 esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
1096 esc_html__( 'Preview topic', 'bbpress' )
1097 ),
1098 );
1099
1100 return $messages;
1101 }
1102 }
1103 endif; // class_exists check
1104
1105 /**
1106 * Setup bbPress Replies Admin
1107 *
1108 * This is currently here to make hooking and unhooking of the admin UI easy.
1109 * It could use dependency injection in the future, but for now this is easier.
1110 *
1111 * @since 2.0.0 bbPress (r2596)
1112 *
1113 * @param WP_Screen $current_screen Current screen object
1114 */
1115 function bbp_admin_replies( $current_screen ) {
1116
1117 // Bail if not a forum screen
1118 if ( empty( $current_screen->post_type ) || ( bbp_get_reply_post_type() !== $current_screen->post_type ) ) {
1119 return;
1120 }
1121
1122 // Init the replies admin
1123 bbp_admin()->replies = new BBP_Replies_Admin();
1124 }
1125