PluginProbe
bbPress / trunk
bbPress vtrunk
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 2.2.2 All 71 releases
bbpress / includes / admin / replies.php

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

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