PluginProbe
bbPress / 2.6.15
bbPress v2.6.15
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 2.6.15, at includes/admin/replies.php

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