PluginProbe
bbPress / 2.6.19
bbPress v2.6.19
2.6.19 2.6.18 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 All 74 releases
bbpress / includes / admin / topics.php

topics.php in bbPress 2.6.19, at includes/admin/topics.php

1,434 lines 47.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * bbPress Topics 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_Topics_Admin' ) ) :
14 /**
15 * Loads bbPress topics admin area
16 *
17 * @package bbPress
18 * @subpackage Administration
19 * @since 2.0.0 bbPress (r3095)
20 */
21 class BBP_Topics_Admin {
22
23 /** Variables *************************************************************/
24
25 /**
26 * @var The post type of this admin component
27 */
28 private $post_type = '';
29
30 private $accepted_forum_moves = array();
31
32 /** Functions *************************************************************/
33
34 /**
35 * The main bbPress topics admin loader
36 *
37 * @since 2.0.0 bbPress (r3095)
38 */
39 public function __construct() {
40 $this->setup_globals();
41 $this->setup_actions();
42 }
43
44 /**
45 * Setup the admin hooks, actions and filters
46 *
47 * @since 2.0.0 bbPress (r3376)
48 * @since 2.6.0 bbPress (r6101) Added bulk actions
49 *
50 * @access private
51 */
52 private function setup_actions() {
53
54 // Messages
55 add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
56
57 // Topic bulk actions, added in WordPress 4.7, see #WP16031.
58 if ( bbp_get_major_wp_version() >= 4.7 ) {
59 add_filter( 'bulk_actions-edit-topic', array( $this, 'bulk_actions' ) );
60 add_filter( 'handle_bulk_actions-edit-topic', array( $this, 'handle_bulk_actions' ), 10, 3 );
61 add_filter( 'bulk_post_updated_messages', array( $this, 'bulk_post_updated_messages' ), 10, 2 );
62 }
63
64 // Topic column headers.
65 add_filter( 'manage_' . $this->post_type . '_posts_columns', array( $this, 'column_headers' ) );
66
67 // Topic columns (in post row)
68 add_action( 'manage_' . $this->post_type . '_posts_custom_column', array( $this, 'column_data' ), 10, 2 );
69 add_filter( 'post_row_actions', array( $this, 'row_actions' ), 10, 2 );
70
71 // Topic meta-box actions
72 add_action( 'add_meta_boxes', array( $this, 'attributes_metabox' ) );
73 add_action( 'add_meta_boxes', array( $this, 'author_metabox' ) );
74 add_action( 'add_meta_boxes', array( $this, 'replies_metabox' ) );
75 add_action( 'add_meta_boxes', array( $this, 'engagements_metabox' ) );
76 add_action( 'add_meta_boxes', array( $this, 'favorites_metabox' ) );
77 add_action( 'add_meta_boxes', array( $this, 'subscriptions_metabox' ) );
78 add_action( 'add_meta_boxes', array( $this, 'comments_metabox' ) );
79 add_action( 'save_post', array( $this, 'save_meta_boxes' ) );
80 add_filter( 'wp_insert_post_data', array( $this, 'filter_post_data' ), 20, 2 );
81
82 // Check if there are any bbp_toggle_topic_* requests on admin_init, also have a message displayed
83 add_action( 'load-edit.php', array( $this, 'toggle_topic' ) );
84 add_action( 'load-edit.php', array( $this, 'toggle_topic_notice' ) );
85
86 // Add ability to filter topics and replies per forum
87 add_filter( 'restrict_manage_posts', array( $this, 'filter_dropdown' ) );
88 add_filter( 'bbp_request', array( $this, 'filter_post_rows' ) );
89
90 // Empty spam
91 add_filter( 'manage_posts_extra_tablenav', array( $this, 'filter_empty_spam' ) );
92
93 // Contextual Help
94 add_action( 'load-edit.php', array( $this, 'edit_help' ) );
95 add_action( 'load-post.php', array( $this, 'new_help' ) );
96 add_action( 'load-post-new.php', array( $this, 'new_help' ) );
97 }
98
99 /**
100 * Admin globals
101 *
102 * @since 2.0.0 bbPress (r3376)
103 *
104 * @access private
105 */
106 private function setup_globals() {
107 $this->post_type = bbp_get_topic_post_type();
108 }
109
110 /** Contextual Help *******************************************************/
111
112 /**
113 * Contextual help for bbPress topic edit page
114 *
115 * @since 2.1.0 bbPress (r3686)
116 */
117 public function edit_help() {
118
119 // Overview
120 get_current_screen()->add_help_tab(
121 array(
122 'id' => 'overview',
123 'title' => __( 'Overview', 'bbpress' ),
124 'content' =>
125 '<p>' . __( 'This screen displays the individual topics on your site. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
126 )
127 );
128
129 // Screen Content
130 get_current_screen()->add_help_tab(
131 array(
132 'id' => 'screen-content',
133 'title' => __( 'Screen Content', 'bbpress' ),
134 'content' =>
135 '<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
136 '<ul>' .
137 '<li>' . __( 'You can hide/display columns based on your needs and decide how many topics to list per screen using the Screen Options tab.', 'bbpress' ) . '</li>' .
138 '<li>' . __( 'You can filter the list of topics by topic status using the text links in the upper left to show All, Published, Draft, Pending, Trashed, Closed, or Spam topics. The default view is to show all topics.', 'bbpress' ) . '</li>' .
139 '<li>' . __( 'You can view topics 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>' .
140 '<li>' . __( 'You can refine the list to show only topics in a specific forum or from a specific month by using the dropdown menus above the topics list. Click the Filter button after making your selection.', 'bbpress' ) . '</li>' .
141 '</ul>'
142 )
143 );
144
145 // Available Actions
146 get_current_screen()->add_help_tab(
147 array(
148 'id' => 'action-links',
149 'title' => __( 'Available Actions', 'bbpress' ),
150 'content' =>
151 '<p>' . __( 'Hovering over a row in the topics list will display action links that allow you to manage your topic. You can perform the following actions:', 'bbpress' ) . '</p>' .
152 '<ul>' .
153 '<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that topic. You can also reach that screen by clicking on the topic title.', 'bbpress' ) . '</li>' .
154 '<li>' . __( '<strong>Stick</strong> will keep the selected topic &#8217;pinned&#8217; to the top the parent forum topic list.', 'bbpress' ) . '</li>' .
155 '<li>' . __( '<strong>Stick <em>(to front)</em></strong> will keep the selected topic &#8217;pinned&#8217; to the top of ALL forums and be visable in any forums topics list.', 'bbpress' ) . '</li>' .
156 '<li>' . __( '<strong>Approve</strong> will change the status from pending to publish.', 'bbpress' ) . '</li>' .
157 '<li>' . __( '<strong>Close</strong> will mark the selected topic as &#8217;closed&#8217; and disable the ability to post new replies to it.', 'bbpress' ) . '</li>' .
158 '<li>' . __( '<strong>Spam</strong> removes your topic from this list and places it in the spam queue, from which you can permanently delete it.', 'bbpress' ) . '</li>' .
159 '<li>' . __( '<strong>Trash</strong> removes your topic from this list and places it in the trash, from which you can permanently delete it.', 'bbpress' ) . '</li>' .
160 '<li>' . __( '<strong>View</strong> will take you to your live site to view the topic.', 'bbpress' ) . '</li>' .
161 '</ul>'
162 )
163 );
164
165 // Bulk Actions
166 get_current_screen()->add_help_tab(
167 array(
168 'id' => 'bulk-actions',
169 'title' => __( 'Bulk Actions', 'bbpress' ),
170 'content' =>
171 '<p>' . __( 'You can also edit, spam, or move multiple topics to the trash at once. Select the topics 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>' .
172 '<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected topics at once. To remove a topic from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
173 )
174 );
175
176 // Help Sidebar
177 get_current_screen()->set_help_sidebar(
178 '<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
179 '<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>', 'bbpress' ) . '</p>' .
180 '<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
181 );
182 }
183
184 /**
185 * Contextual help for bbPress topic edit page
186 *
187 * @since 2.1.0 bbPress (r3686)
188 */
189 public function new_help() {
190
191 $customize_display = '<p>' . __( 'The title field and the big topic 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>';
192
193 get_current_screen()->add_help_tab(
194 array(
195 'id' => 'customize-display',
196 'title' => __( 'Customizing This Display', 'bbpress' ),
197 'content' => $customize_display,
198 )
199 );
200
201 get_current_screen()->add_help_tab(
202 array(
203 'id' => 'title-topic-editor',
204 'title' => __( 'Title and Topic Editor', 'bbpress' ),
205 'content' =>
206 '<p>' . __( '<strong>Title</strong> - Enter a title for your topic. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
207 '<p>' . __( '<strong>Topic Editor</strong> - Enter the text for your topic. 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 topic text. You can insert media files by clicking the icons above the topic 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 topic editor.', 'bbpress' ) . '</p>'
208 )
209 );
210
211 $publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your topic 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 topic 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 topic to be published in the future or backdate a topic.', 'bbpress' ) . '</p>';
212
213 if ( current_theme_supports( 'topic-thumbnails' ) && post_type_supports( bbp_get_topic_post_type(), 'thumbnail' ) ) {
214 $publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your topic without inserting it. This is usually useful only if your theme makes use of the featured image as a topic thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
215 }
216
217 get_current_screen()->add_help_tab(
218 array(
219 'id' => 'topic-attributes',
220 'title' => __( 'Topic Attributes', 'bbpress' ),
221 'content' =>
222 '<p>' . __( 'Select the attributes that your topic should have:', 'bbpress' ) . '</p>' .
223 '<ul>' .
224 '<li>' . __( '<strong>Forum</strong> dropdown determines the parent forum that the topic belongs to. Select the forum or category from the dropdown, or leave the default "No forum" to post the topic without an assigned forum.', 'bbpress' ) . '</li>' .
225 '<li>' . __( '<strong>Topic Type</strong> dropdown indicates the sticky status of the topic. Selecting the super sticky option would stick the topic to the front of your forums, i.e. the topic index, sticky option would stick the topic to its respective forum. Selecting normal would not stick the topic anywhere.', 'bbpress' ) . '</li>' .
226 '</ul>'
227 )
228 );
229
230 get_current_screen()->add_help_tab(
231 array(
232 'id' => 'publish-box',
233 'title' => __( 'Publish Box', 'bbpress' ),
234 'content' => $publish_box,
235 )
236 );
237
238 get_current_screen()->set_help_sidebar(
239 '<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
240 '<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>', 'bbpress' ) . '</p>' .
241 '<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
242 );
243 }
244
245 /**
246 * Add spam/unspam bulk actions to the bulk action dropdown.
247 *
248 * @since 2.6.0 bbPress (r6101)
249 *
250 * @param array $actions The list of bulk actions.
251 * @return array The filtered list of bulk actions.
252 */
253 public function bulk_actions( $actions ) {
254
255 if ( current_user_can( 'moderate' ) ) {
256 if ( bbp_get_spam_status_id() === get_query_var( 'post_status' ) ) {
257 $actions['unspam'] = esc_html__( 'Unspam', 'bbpress' );
258 } else {
259 $actions['spam'] = esc_html__( 'Spam', 'bbpress' );
260 }
261 }
262
263 return $actions;
264 }
265
266 /**
267 * Add custom bulk action updated messages for topics.
268 *
269 * @since 2.6.0 bbPress (r6101)
270 *
271 * @param array $bulk_messages Arrays of messages, each keyed by the corresponding post type.
272 * @param array $bulk_counts Array of item counts for each message, used to build internationalized strings.
273 */
274 public function bulk_post_updated_messages( $bulk_messages, $bulk_counts ) {
275 /* translators: %s: Number of topics */
276 $bulk_messages['topic']['updated'] = _n( '%s topic updated.', '%s topics updated.', $bulk_counts['updated'], 'bbpress' );
277 $bulk_messages['topic']['locked'] = ( 1 === $bulk_counts['locked'] )
278 ? __( '1 topic not updated, somebody is editing it.', 'bbpress' )
279 /* translators: %s: Number of topics */
280 : _n( '%s topic not updated, somebody is editing it.', '%s topics not updated, somebody is editing them.', $bulk_counts['locked'], 'bbpress' );
281
282 return $bulk_messages;
283 }
284
285 /**
286 * Handle spam/unspam bulk actions.
287 *
288 * @since 2.6.0 bbPress (r6101)
289 *
290 * @param string $sendback The sendback URL.
291 * @param string $doaction The action to be taken.
292 * @param array $post_ids The post IDS to take the action on.
293 * @return string The sendback URL.
294 */
295 public function handle_bulk_actions( $sendback, $doaction, $post_ids ) {
296
297 $sendback = remove_query_arg( array( 'spam', 'unspam' ), $sendback );
298 $updated = $locked = 0;
299
300 if ( 'spam' === $doaction ) {
301
302 foreach ( (array) $post_ids as $post_id ) {
303 if ( ! current_user_can( 'moderate', $post_id ) ) {
304 wp_die( esc_html__( 'Sorry, you are not allowed to spam this item.', 'bbpress' ) );
305 }
306
307 if ( wp_check_post_lock( $post_id ) ) {
308 $locked++;
309 continue;
310 }
311
312 if ( ! bbp_spam_topic( $post_id ) ) {
313 wp_die( esc_html__( 'Error in spamming topic.', 'bbpress' ) );
314 }
315
316 ++$updated;
317 }
318
319 $sendback = add_query_arg(
320 array(
321 'updated' => $updated,
322 'ids' => implode( ',', $post_ids ),
323 'locked' => $locked
324 ),
325 $sendback
326 );
327
328 } elseif ( 'unspam' === $doaction ) {
329
330 foreach ( (array) $post_ids as $post_id ) {
331 if ( ! current_user_can( 'moderate', $post_id ) ) {
332 wp_die( esc_html__( 'Sorry, you are not allowed to unspam this topic.', 'bbpress' ) );
333 }
334
335 if ( wp_check_post_lock( $post_id ) ) {
336 $locked++;
337 continue;
338 }
339
340 if ( ! bbp_unspam_topic( $post_id ) ) {
341 wp_die( esc_html__( 'Error in unspamming topic.', 'bbpress' ) );
342 }
343
344 ++$updated;
345 }
346
347 $sendback = add_query_arg(
348 array(
349 'updated' => $updated,
350 'ids' => implode( ',', $post_ids ),
351 'locked' => $locked
352 ),
353 $sendback
354 );
355 }
356
357 return $sendback;
358 }
359
360 /**
361 * Add the topic attributes meta-box
362 *
363 * @since 2.1.0 bbPress (r3749)
364 */
365 public function attributes_metabox() {
366 add_meta_box(
367 'bbp_topic_attributes',
368 esc_html__( 'Topic Attributes', 'bbpress' ),
369 'bbp_topic_metabox',
370 $this->post_type,
371 'side',
372 'high'
373 );
374 }
375
376 /**
377 * Add the author info meta-box
378 *
379 * @since 2.0.0 bbPress (r3120)
380 */
381 public function author_metabox() {
382
383 // Bail if post_type is not a topic
384 if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
385 return;
386 }
387
388 // Add the meta-box
389 add_meta_box(
390 'bbp_author_metabox',
391 esc_html__( 'Author Information', 'bbpress' ),
392 'bbp_author_metabox',
393 $this->post_type,
394 'side',
395 'high'
396 );
397 }
398
399 /**
400 * Add the replies meta-box
401 *
402 * Allows viewing & moderating of replies to a topic, based on the way
403 * comments are visible on a blog post.
404 *
405 * @since 2.6.0 bbPress (r5886)
406 */
407 public function replies_metabox() {
408
409 // Bail if post_type is not a reply
410 if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
411 return;
412 }
413
414 // Add the meta-box
415 add_meta_box(
416 'bbp_topic_replies_metabox',
417 esc_html__( 'Replies', 'bbpress' ),
418 'bbp_topic_replies_metabox',
419 $this->post_type,
420 'normal',
421 'high'
422 );
423 }
424
425 /**
426 * Add the engagements meta-box
427 *
428 * Allows viewing of users who have engaged in a topic.
429 *
430 * @since 2.6.0 bbPress (r6334)
431 */
432 public function engagements_metabox() {
433
434 // Bail when creating a new topic
435 if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
436 return;
437 }
438
439 // Bail if no engagements
440 if ( ! bbp_is_engagements_active() ) {
441 return;
442 }
443
444 // Add the meta-box
445 add_meta_box(
446 'bbp_topic_engagements_metabox',
447 esc_html__( 'Engagements', 'bbpress' ),
448 'bbp_topic_engagements_metabox',
449 $this->post_type,
450 'side',
451 'low'
452 );
453 }
454
455 /**
456 * Add the favorites meta-box
457 *
458 * Allows viewing of users who have favorited a topic.
459 *
460 * @since 2.6.0 bbPress (r6197)
461 */
462 public function favorites_metabox() {
463
464 // Bail if post_type is not a reply
465 if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
466 return;
467 }
468
469 // Bail if no favorites
470 if ( ! bbp_is_favorites_active() ) {
471 return;
472 }
473
474 // Add the meta-box
475 add_meta_box(
476 'bbp_topic_favorites_metabox',
477 esc_html__( 'Favorites', 'bbpress' ),
478 'bbp_topic_favorites_metabox',
479 $this->post_type,
480 'normal',
481 'high'
482 );
483 }
484
485 /**
486 * Add the subscriptions meta-box
487 *
488 * Allows viewing of users who have subscribed to a topic.
489 *
490 * @since 2.6.0 bbPress (r6197)
491 */
492 public function subscriptions_metabox() {
493
494 // Bail if post_type is not a reply
495 if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
496 return;
497 }
498
499 // Bail if no subscriptions
500 if ( ! bbp_is_subscriptions_active() ) {
501 return;
502 }
503
504 // Add the meta-box
505 add_meta_box(
506 'bbp_topic_subscriptions_metabox',
507 esc_html__( 'Subscriptions', 'bbpress' ),
508 'bbp_topic_subscriptions_metabox',
509 $this->post_type,
510 'normal',
511 'high'
512 );
513 }
514
515 /**
516 * Remove comments & discussion meta-boxes if comments are not supported
517 *
518 * @since 2.6.0 bbPress (r6186)
519 */
520 public function comments_metabox() {
521 if ( ! post_type_supports( $this->post_type, 'comments' ) ) {
522 remove_meta_box( 'commentstatusdiv', $this->post_type, 'normal' );
523 remove_meta_box( 'commentsdiv', $this->post_type, 'normal' );
524 }
525 }
526
527 /**
528 * Pass the topic attributes for processing
529 *
530 * @since 2.6.0 bbPress (r6056)
531 *
532 * @param int $topic_id Topic id
533 * @return int Parent id
534 */
535 public function save_meta_boxes( $topic_id ) {
536 $accepted_move = isset( $this->accepted_forum_moves[ $topic_id ] )
537 ? $this->accepted_forum_moves[ $topic_id ]
538 : array();
539 unset( $this->accepted_forum_moves[ $topic_id ] );
540
541 // Revisions can also fire save_post with the metabox nonce.
542 if ( ! bbp_is_topic( $topic_id ) ) {
543 return $topic_id;
544 }
545
546 // Bail if doing an autosave
547 if ( bbp_doing_autosave() ) {
548 return $topic_id;
549 }
550
551 // Bail if not a post request
552 if ( ! bbp_is_post_request() ) {
553 return $topic_id;
554 }
555
556 // Check action exists
557 if ( empty( $_POST['action'] ) ) {
558 return $topic_id;
559 }
560
561 // Nonce check
562 if ( empty( $_POST['bbp_topic_metabox'] ) || ! wp_verify_nonce( $_POST['bbp_topic_metabox'], 'bbp_topic_metabox_save' ) ) {
563 return $topic_id;
564 }
565
566 // Bail if current user cannot edit this topic
567 if ( ! current_user_can( 'edit_topic', $topic_id ) && empty( $accepted_move ) ) {
568 return $topic_id;
569 }
570
571 // Use the parent accepted by WordPress and the destination filter.
572 $forum_id = ! empty( $accepted_move )
573 ? $accepted_move['new']
574 : bbp_get_topic_forum_id( $topic_id );
575
576 // Get topic author data
577 $anonymous_data = bbp_filter_anonymous_post_data();
578 $author_id = bbp_get_topic_author_id( $topic_id );
579 $is_edit = ( isset( $_POST['hidden_post_status'] ) && ( 'draft' !== $_POST['hidden_post_status'] ) );
580
581 // Formally update the topic
582 bbp_update_topic( $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit );
583 if ( ! empty( $accepted_move['old'] ) ) {
584 bbp_move_topic_handler( $topic_id, $accepted_move['old'], $accepted_move['new'] );
585 }
586
587 // Allow other fun things to happen
588 do_action( 'bbp_topic_attributes_metabox_save', $topic_id, $forum_id );
589 do_action( 'bbp_author_metabox_save', $topic_id, $anonymous_data );
590
591 return $topic_id;
592 }
593
594 /**
595 * Keep admin topic moves within forums the current user may use.
596 *
597 * @since 2.6.19 bbPress (r7688)
598 *
599 * @param array $data Sanitized post data.
600 * @param array $postarr Unprocessed post data.
601 * @return array Filtered post data.
602 */
603 public function filter_post_data( $data, $postarr ) {
604
605 // Only filter administration saves of existing topics.
606 if ( ! is_admin() || empty( $postarr['ID'] ) || ( bbp_get_topic_post_type() !== $data['post_type'] ) ) {
607 return $data;
608 }
609
610 $topic = bbp_get_topic( $postarr['ID'] );
611 if ( empty( $topic ) || (int) $topic->post_parent === (int) $data['post_parent'] ) {
612 return $data;
613 }
614
615 $old_forum_id = (int) $topic->post_parent;
616 $new_forum_id = (int) $data['post_parent'];
617 $is_new = ( 'auto-draft' === $topic->post_status );
618 $is_editor = ! empty( $_POST['action'] ) && ( 'editpost' === $_POST['action'] );
619
620 // Other admin save paths cannot complete a bbPress topic move.
621 if ( ! $is_editor && ! $is_new ) {
622 $data['post_parent'] = $topic->post_parent;
623 return $data;
624 }
625
626 // Match the front-end topic move checks before WordPress changes post_parent.
627 if (
628 ! $is_editor
629 || empty( $_POST['bbp_topic_metabox'] )
630 || ! is_string( $_POST['bbp_topic_metabox'] )
631 || ! wp_verify_nonce( $_POST['bbp_topic_metabox'], 'bbp_topic_metabox_save' )
632 || ! current_user_can( 'edit_topic', $topic->ID )
633 || ( $is_new && ! current_user_can( 'publish_topics' ) )
634 || ( ! empty( $old_forum_id ) && ! current_user_can( 'edit_forum', $old_forum_id ) )
635 || ! bbp_get_forum( $new_forum_id )
636 || bbp_is_forum_category( $new_forum_id )
637 || ! current_user_can( 'read_forum', $new_forum_id )
638 || ( bbp_is_forum_closed( $new_forum_id ) && ! current_user_can( 'edit_forum', $new_forum_id ) )
639 ) {
640 if ( $is_new ) {
641 wp_die(
642 esc_html__( 'The selected forum is not available for this topic.', 'bbpress' ),
643 '',
644 array(
645 'response' => 403,
646 'back_link' => true,
647 )
648 );
649 }
650 $data['post_parent'] = $topic->post_parent;
651 } else {
652 $this->accepted_forum_moves[ $topic->ID ] = array(
653 'old' => $old_forum_id,
654 'new' => $new_forum_id,
655 );
656 }
657
658 return $data;
659 }
660
661 /**
662 * Toggle topic
663 *
664 * Handles the admin-side opening/closing, sticking/unsticking and
665 * spamming/unspamming of topics
666 *
667 * @since 2.0.0 bbPress (r3095)
668 */
669 public function toggle_topic() {
670
671 // Bail if not a topic toggle action
672 if ( ! bbp_is_get_request() || empty( $_GET['action'] ) || empty( $_GET['topic_id'] ) ) {
673 return;
674 }
675
676 // Bail if not an allowed action
677 $action = sanitize_key( $_GET['action'] );
678 if ( empty( $action ) || ! in_array( $action, $this->get_allowed_action_toggles(), true ) ) {
679 return;
680 }
681
682 // Bail if topic is missing
683 $topic_id = bbp_get_topic_id( $_GET['topic_id'] );
684 if ( ! bbp_get_topic( $topic_id ) ) {
685 wp_die( esc_html__( 'The topic was not found.', 'bbpress' ) );
686 }
687
688 // What is the user doing here?
689 if ( ! current_user_can( 'moderate', $topic_id ) ) {
690 wp_die( esc_html__( 'You do not have permission to do that.', 'bbpress' ) );
691 }
692
693 // Super stickies affect every forum and require global moderation
694 if ( ( 'bbp_toggle_topic_stick' === $action ) && ! current_user_can( 'moderate' ) && ( bbp_is_topic_super_sticky( $topic_id ) || ( ! bbp_is_topic_sticky( $topic_id ) && ! empty( $_GET['super'] ) && ( '1' === $_GET['super'] ) ) ) ) {
695 wp_die( esc_html__( 'You do not have permission to do that.', 'bbpress' ) );
696 }
697
698 // Defaults
699 $post_data = array( 'ID' => $topic_id );
700 $message = '';
701 $success = false;
702
703 switch ( $action ) {
704 case 'bbp_toggle_topic_approve' :
705 check_admin_referer( 'approve-topic_' . $topic_id );
706
707 $is_approve = bbp_is_topic_public( $topic_id );
708 $message = ( true === $is_approve )
709 ? 'unapproved'
710 : 'approved';
711 $success = ( true === $is_approve )
712 ? bbp_unapprove_topic( $topic_id )
713 : bbp_approve_topic( $topic_id );
714
715 break;
716
717 case 'bbp_toggle_topic_close' :
718 check_admin_referer( 'close-topic_' . $topic_id );
719
720 $is_open = bbp_is_topic_open( $topic_id );
721 $message = ( true === $is_open )
722 ? 'closed'
723 : 'opened';
724 $success = ( true === $is_open )
725 ? bbp_close_topic( $topic_id )
726 : bbp_open_topic( $topic_id );
727
728 break;
729
730 case 'bbp_toggle_topic_stick' :
731 check_admin_referer( 'stick-topic_' . $topic_id );
732
733 $is_sticky = bbp_is_topic_sticky( $topic_id );
734 $is_super = ( false === $is_sticky ) && ! empty( $_GET['super'] ) && ( '1' === $_GET['super'] )
735 ? true
736 : false;
737 $message = ( true === $is_sticky )
738 ? 'unstuck'
739 : 'stuck';
740 $message = ( true === $is_super )
741 ? 'super_sticky'
742 : $message;
743 $success = ( true === $is_sticky )
744 ? bbp_unstick_topic( $topic_id )
745 : bbp_stick_topic( $topic_id, $is_super );
746
747 break;
748
749 case 'bbp_toggle_topic_spam' :
750 check_admin_referer( 'spam-topic_' . $topic_id );
751
752 $is_spam = bbp_is_topic_spam( $topic_id );
753 $message = ( true === $is_spam )
754 ? 'unspammed'
755 : 'spammed';
756 $success = ( true === $is_spam )
757 ? bbp_unspam_topic( $topic_id )
758 : bbp_spam_topic( $topic_id );
759
760 break;
761 }
762
763 // Setup the message
764 $retval = array(
765 'bbp_topic_toggle_notice' => $message,
766 'topic_id' => $topic_id
767 );
768
769 // Prepare for failure
770 if ( ( false === $success ) || is_wp_error( $success ) ) {
771 $retval['failed'] = '1';
772 }
773
774 // Filter all message args
775 $retval = apply_filters( 'bbp_toggle_topic_action_admin', $retval, $topic_id, $action );
776
777 // Do additional topic toggle actions (admin side)
778 do_action( 'bbp_toggle_topic_admin', $success, $post_data, $action, $retval );
779
780 // Redirect back to the topic
781 $redirect = add_query_arg( $retval, remove_query_arg( array( 'action', 'topic_id' ) ) );
782 bbp_redirect( $redirect );
783 }
784
785 /**
786 * Toggle topic notices
787 *
788 * Display the success/error notices from
789 * {@link BBP_Admin::toggle_topic()}
790 *
791 * @since 2.0.0 bbPress (r3095)
792 */
793 public function toggle_topic_notice() {
794
795 // Bail if missing topic toggle action
796 if ( ! bbp_is_get_request() || empty( $_GET['topic_id'] ) || empty( $_GET['bbp_topic_toggle_notice'] ) ) {
797 return;
798 }
799
800 // Bail if not an allowed notice
801 $notice = sanitize_key( $_GET['bbp_topic_toggle_notice'] );
802 if ( empty( $notice ) || ! in_array( $notice, $this->get_allowed_notice_toggles(), true ) ) {
803 return;
804 }
805
806 // Bail if no topic_id or notice
807 $topic_id = bbp_get_topic_id( $_GET['topic_id'] );
808 if ( empty( $topic_id ) ) {
809 return;
810 }
811
812 // Bail if topic is missing
813 if ( ! bbp_get_topic( $topic_id ) ) {
814 return;
815 }
816
817 // Use the title in the responses
818 $topic_title = bbp_get_topic_title( $topic_id );
819 $is_failure = ! empty( $_GET['failed'] );
820 $message = '';
821
822 // Which notice?
823 switch ( $notice ) {
824 case 'opened' :
825 $message = ( true === $is_failure )
826 /* translators: %1$s: Topic title */
827 ? sprintf( esc_html__( 'There was a problem opening the topic "%1$s".', 'bbpress' ), $topic_title )
828 /* translators: %1$s: Topic title */
829 : sprintf( esc_html__( 'Topic "%1$s" successfully opened.', 'bbpress' ), $topic_title );
830 break;
831
832 case 'closed' :
833 $message = ( true === $is_failure )
834 /* translators: %1$s: Topic title */
835 ? sprintf( esc_html__( 'There was a problem closing the topic "%1$s".', 'bbpress' ), $topic_title )
836 /* translators: %1$s: Topic title */
837 : sprintf( esc_html__( 'Topic "%1$s" successfully closed.', 'bbpress' ), $topic_title );
838 break;
839
840 case 'super_sticky' :
841 $message = ( true === $is_failure )
842 /* translators: %1$s: Topic title */
843 ? sprintf( esc_html__( 'There was a problem sticking the topic "%1$s" to front.', 'bbpress' ), $topic_title )
844 /* translators: %1$s: Topic title */
845 : sprintf( esc_html__( 'Topic "%1$s" successfully stuck to front.', 'bbpress' ), $topic_title );
846 break;
847
848 case 'stuck' :
849 $message = ( true === $is_failure )
850 /* translators: %1$s: Topic title */
851 ? sprintf( esc_html__( 'There was a problem sticking the topic "%1$s".', 'bbpress' ), $topic_title )
852 /* translators: %1$s: Topic title */
853 : sprintf( esc_html__( 'Topic "%1$s" successfully stuck.', 'bbpress' ), $topic_title );
854 break;
855
856 case 'unstuck' :
857 $message = ( true === $is_failure )
858 /* translators: %1$s: Topic title */
859 ? sprintf( esc_html__( 'There was a problem unsticking the topic "%1$s".', 'bbpress' ), $topic_title )
860 /* translators: %1$s: Topic title */
861 : sprintf( esc_html__( 'Topic "%1$s" successfully unstuck.', 'bbpress' ), $topic_title );
862 break;
863
864 case 'spammed' :
865 $message = ( true === $is_failure )
866 /* translators: %1$s: Topic title */
867 ? sprintf( esc_html__( 'There was a problem marking the topic "%1$s" as spam.', 'bbpress' ), $topic_title )
868 /* translators: %1$s: Topic title */
869 : sprintf( esc_html__( 'Topic "%1$s" successfully marked as spam.', 'bbpress' ), $topic_title );
870 break;
871
872 case 'unspammed' :
873 $message = ( true === $is_failure )
874 /* translators: %1$s: Topic title */
875 ? sprintf( esc_html__( 'There was a problem unmarking the topic "%1$s" as spam.', 'bbpress' ), $topic_title )
876 /* translators: %1$s: Topic title */
877 : sprintf( esc_html__( 'Topic "%1$s" successfully unmarked as spam.', 'bbpress' ), $topic_title );
878 break;
879
880 case 'approved' :
881 $message = ( true === $is_failure )
882 /* translators: %1$s: Topic title */
883 ? sprintf( esc_html__( 'There was a problem approving the topic "%1$s".', 'bbpress' ), $topic_title )
884 /* translators: %1$s: Topic title */
885 : sprintf( esc_html__( 'Topic "%1$s" successfully approved.', 'bbpress' ), $topic_title );
886 break;
887
888 case 'unapproved' :
889 $message = ( true === $is_failure )
890 /* translators: %1$s: Topic title */
891 ? sprintf( esc_html__( 'There was a problem unapproving the topic "%1$s".', 'bbpress' ), $topic_title )
892 /* translators: %1$s: Topic title */
893 : sprintf( esc_html__( 'Topic "%1$s" successfully unapproved.', 'bbpress' ), $topic_title );
894 break;
895 }
896
897 // Do additional topic toggle notice filters (admin side)
898 $message = apply_filters( 'bbp_toggle_topic_notice_admin', $message, $topic_id, $notice, $is_failure );
899 $class = ( true === $is_failure )
900 ? 'error'
901 : 'updated';
902
903 // Add the notice
904 bbp_admin()->add_notice( $message, $class, true );
905 }
906
907 /**
908 * Returns an array of keys used to sort row actions
909 *
910 * @since 2.6.0 bbPress (r6772)
911 *
912 * @return array
913 */
914 private function get_row_action_sort_order() {
915
916 // Filter & return
917 return (array) apply_filters(
918 'bbp_admin_topics_row_action_sort_order',
919 array(
920 'edit',
921 'stick',
922 'approved',
923 'unapproved',
924 'closed',
925 'spam',
926 'unspam',
927 'trash',
928 'untrash',
929 'delete',
930 'view'
931 )
932 );
933 }
934
935 /**
936 * Returns an array of notice toggles
937 *
938 * @since 2.6.0 bbPress (r6397)
939 *
940 * @return array
941 */
942 private function get_allowed_notice_toggles() {
943
944 // Filter & return
945 return (array) apply_filters(
946 'bbp_admin_topics_allowed_notice_toggles',
947 array(
948 'opened',
949 'closed',
950 'super_sticky',
951 'stuck',
952 'unstuck',
953 'spammed',
954 'unspammed',
955 'approved',
956 'unapproved'
957 )
958 );
959 }
960
961 /**
962 * Returns an array of notice toggles
963 *
964 * @since 2.6.0 bbPress (r6397)
965 *
966 * @return array
967 */
968 private function get_allowed_action_toggles() {
969
970 // Filter & return
971 return (array) apply_filters(
972 'bbp_admin_topics_allowed_action_toggles',
973 array(
974 'bbp_toggle_topic_close',
975 'bbp_toggle_topic_stick',
976 'bbp_toggle_topic_spam',
977 'bbp_toggle_topic_approve'
978 )
979 );
980 }
981
982 /**
983 * Manage the column headers for the topics page
984 *
985 * @since 2.4.0 bbPress (r4991)
986 *
987 * @param array $columns The columns
988 *
989 * @return array $columns bbPress topic columns
990 */
991 public function column_headers( $columns ) {
992 $columns = array(
993 'cb' => '<input type="checkbox" />',
994 'title' => esc_html__( 'Topics', 'bbpress' ),
995 'bbp_topic_forum' => esc_html__( 'Forum', 'bbpress' ),
996 'bbp_topic_reply_count' => esc_html__( 'Replies', 'bbpress' ),
997 'bbp_topic_voice_count' => esc_html__( 'Voices', 'bbpress' ),
998 'bbp_topic_author' => esc_html__( 'Author', 'bbpress' ),
999 'bbp_topic_created' => esc_html__( 'Created', 'bbpress' ),
1000 'bbp_topic_freshness' => esc_html__( 'Last Post', 'bbpress' )
1001 );
1002
1003 // Filter & return
1004 return (array) apply_filters( 'bbp_admin_topics_column_headers', $columns );
1005 }
1006
1007 /**
1008 * Print extra columns for the topics page
1009 *
1010 * @since 2.4.0 bbPress (r4991)
1011 *
1012 * @param string $column Column
1013 * @param int $topic_id Topic id
1014 */
1015 public function column_data( $column, $topic_id ) {
1016
1017 // Get topic forum ID
1018 $forum_id = bbp_get_topic_forum_id( $topic_id );
1019
1020 // Populate column data
1021 switch ( $column ) {
1022
1023 // Forum
1024 case 'bbp_topic_forum' :
1025
1026 // Get title
1027 $forum_title = ! empty( $forum_id )
1028 ? bbp_get_forum_title( $forum_id )
1029 : '';
1030
1031 // Output forum name
1032 if ( ! empty( $forum_title ) ) {
1033 echo $forum_title;
1034
1035 // Output dash
1036 } else {
1037 ?>
1038 <span aria-hidden="true">&mdash;</span>
1039 <span class="screen-reader-text"><?php esc_html_e( 'No forum', 'bbpress' ); ?></span>
1040 <?php
1041 }
1042
1043 break;
1044
1045 // Reply Count
1046 case 'bbp_topic_reply_count' :
1047 bbp_topic_reply_count( $topic_id );
1048 break;
1049
1050 // Reply Count
1051 case 'bbp_topic_voice_count' :
1052 bbp_topic_voice_count( $topic_id );
1053 break;
1054
1055 // Author
1056 case 'bbp_topic_author' :
1057 bbp_topic_author_display_name( $topic_id );
1058 break;
1059
1060 // Freshness
1061 case 'bbp_topic_created':
1062 printf( '%1$s <br /> %2$s',
1063 get_the_date(),
1064 esc_attr( get_the_time() )
1065 );
1066
1067 break;
1068
1069 // Freshness
1070 case 'bbp_topic_freshness' :
1071 $last_active = bbp_get_topic_last_active_time( $topic_id, false );
1072 if ( ! empty( $last_active ) ) {
1073 echo esc_html( $last_active );
1074 } else {
1075 esc_html_e( 'No Replies', 'bbpress' ); // This should never happen
1076 }
1077
1078 break;
1079
1080 // Do an action for anything else
1081 default :
1082 do_action( 'bbp_admin_topics_column_data', $column, $topic_id );
1083 break;
1084 }
1085 }
1086
1087 /**
1088 * Topic Row actions
1089 *
1090 * Remove the quick-edit action link under the topic title and add the
1091 * content and close/stick/spam links
1092 *
1093 * @since 2.4.0 bbPress (r4991)
1094 *
1095 * @param array $actions Actions
1096 * @param object $topic Topic object
1097 *
1098 * @return array $actions Actions
1099 */
1100 public function row_actions( $actions = array(), $topic = false ) {
1101
1102 // Disable quick edit (too much to do here)
1103 unset( $actions['inline hide-if-no-js'] );
1104
1105 // View link
1106 $view_link = bbp_get_topic_permalink( $topic->ID );
1107
1108 // Maybe add view=all
1109 if ( ! in_array( $topic->post_status, array( bbp_get_closed_status_id(), bbp_get_public_status_id() ), true ) ) {
1110 $view_link = bbp_add_view_all( $view_link, true );
1111 }
1112
1113 // Show view link if it's not set, the topic is trashed and the user can view trashed topics
1114 if ( empty( $actions['view'] ) && ( bbp_get_trash_status_id() === $topic->post_status ) && current_user_can( 'view_trash' ) ) {
1115 /* translators: %s: Topic title */
1116 $actions['view'] = '<a href="' . esc_url( $view_link ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;', 'bbpress' ), bbp_get_topic_title( $topic->ID ) ) ) . '" rel="permalink">' . esc_html__( 'View', 'bbpress' ) . '</a>';
1117 }
1118
1119 // Only show the actions if the user is capable of viewing them :)
1120 if ( current_user_can( 'moderate', $topic->ID ) ) {
1121
1122 // Pending
1123 // Show the 'approve' and 'view' link on pending posts only and 'unapprove' on published posts only
1124 $args = array(
1125 'topic_id' => $topic->ID,
1126 'action' => 'bbp_toggle_topic_approve'
1127 );
1128 $approve_uri = wp_nonce_url( add_query_arg( $args, remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'approve-topic_' . $topic->ID );
1129 if ( bbp_is_topic_public( $topic->ID ) ) {
1130 $actions['unapproved'] = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Unapprove this topic', 'bbpress' ) . '">' . _x( 'Unapprove', 'Unapprove Topic', 'bbpress' ) . '</a>';
1131 } else {
1132
1133 // Do not show 'approve' if already public
1134 if ( ! bbp_is_topic_public( $topic->ID ) ) {
1135 $actions['approved'] = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Approve this topic', 'bbpress' ) . '">' . _x( 'Approve', 'Approve Topic', 'bbpress' ) . '</a>';
1136 }
1137
1138 // Modify the view link
1139 /* translators: %s: Topic title */
1140 $actions['view'] = '<a href="' . esc_url( $view_link ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;', 'bbpress' ), bbp_get_topic_title( $topic->ID ) ) ) . '" rel="permalink">' . esc_html__( 'View', 'bbpress' ) . '</a>';
1141 }
1142
1143 // Close
1144 // Show the 'close' and 'open' link on published and closed posts only
1145 if ( bbp_is_topic_public( $topic->ID ) ) {
1146 $args = array(
1147 'topic_id' => $topic->ID,
1148 'action' => 'bbp_toggle_topic_close'
1149 );
1150 $close_uri = wp_nonce_url( add_query_arg( $args, remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'close-topic_' . $topic->ID );
1151 if ( bbp_is_topic_open( $topic->ID ) ) {
1152 $actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Close this topic', 'bbpress' ) . '">' . _x( 'Close', 'Close a Topic', 'bbpress' ) . '</a>';
1153 } else {
1154 $actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Open this topic', 'bbpress' ) . '">' . _x( 'Open', 'Open a Topic', 'bbpress' ) . '</a>';
1155 }
1156 }
1157
1158 // Sticky
1159 // Dont show sticky if topic is spam, trash or pending
1160 if ( ! bbp_is_topic_spam( $topic->ID ) && ! bbp_is_topic_trash( $topic->ID ) && ! bbp_is_topic_pending( $topic->ID ) && ( ! bbp_is_topic_super_sticky( $topic->ID ) || current_user_can( 'moderate' ) ) ) {
1161 $args = array(
1162 'topic_id' => $topic->ID,
1163 'action' => 'bbp_toggle_topic_stick'
1164 );
1165 $stick_uri = wp_nonce_url( add_query_arg( $args, remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'stick-topic_' . $topic->ID );
1166 if ( bbp_is_topic_sticky( $topic->ID ) ) {
1167 $actions['stick'] = '<a href="' . esc_url( $stick_uri ) . '" title="' . esc_attr__( 'Unstick this topic', 'bbpress' ) . '">' . esc_html__( 'Unstick', 'bbpress' ) . '</a>';
1168 } else {
1169 $actions['stick'] = '<a href="' . esc_url( $stick_uri ) . '" title="' . esc_attr__( 'Stick this topic to its forum', 'bbpress' ) . '">' . esc_html__( 'Stick', 'bbpress' ) . '</a>';
1170 if ( current_user_can( 'moderate' ) ) {
1171 $args = array(
1172 'topic_id' => $topic->ID,
1173 'action' => 'bbp_toggle_topic_stick',
1174 'super' => '1'
1175 );
1176 $super_uri = wp_nonce_url( add_query_arg( $args, remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'stick-topic_' . $topic->ID );
1177 $actions['stick'] .= ' <a href="' . esc_url( $super_uri ) . '" title="' . esc_attr__( 'Stick this topic to front', 'bbpress' ) . '">' . esc_html__( '(to front)', 'bbpress' ) . '</a>';
1178 }
1179 }
1180 }
1181
1182 // Spam
1183 $args = array(
1184 'topic_id' => $topic->ID,
1185 'action' => 'bbp_toggle_topic_spam'
1186 );
1187 $spam_uri = wp_nonce_url( add_query_arg( $args, remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'spam-topic_' . $topic->ID );
1188 if ( ! bbp_is_topic_spam( $topic->ID ) ) {
1189 $actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark this topic as spam', 'bbpress' ) . '">' . esc_html__( 'Spam', 'bbpress' ) . '</a>';
1190 } else {
1191 $actions['unspam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark the topic as not spam', 'bbpress' ) . '">' . esc_html__( 'Not Spam', 'bbpress' ) . '</a>';
1192 }
1193 }
1194
1195 // Do not show trash links for spam topics, or spam links for trashed topics
1196 if ( current_user_can( 'delete_topic', $topic->ID ) ) {
1197 $trash_days = bbp_get_trash_days( bbp_get_topic_post_type() );
1198
1199 if ( bbp_get_trash_status_id() === $topic->post_status ) {
1200 $post_type_object = get_post_type_object( bbp_get_topic_post_type() );
1201 $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', $topic->ID ) ), 'untrash-post_' . $topic->ID ) ) . "'>" . esc_html__( 'Restore', 'bbpress' ) . '</a>';
1202 } elseif ( ! empty( $trash_days ) ) {
1203 $actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $topic->ID ) ) . "'>" . esc_html__( 'Trash', 'bbpress' ) . '</a>';
1204 }
1205
1206 if ( ( bbp_get_trash_status_id() === $topic->post_status ) || empty( $trash_days ) ) {
1207 $actions['delete'] = "<a class='submitdelete' title='" . esc_attr__( 'Delete this item permanently', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $topic->ID, '', true ) ) . "'>" . esc_html__( 'Delete Permanently', 'bbpress' ) . '</a>';
1208 }
1209 }
1210
1211 // Sort & return
1212 return $this->sort_row_actions( $actions );
1213 }
1214
1215 /**
1216 * Sort row actions by key
1217 *
1218 * @since 2.6.0 bbPress (r6772)
1219 *
1220 * @param array $actions
1221 *
1222 * @return array
1223 */
1224 private function sort_row_actions( $actions = array() ) {
1225
1226 // Return value
1227 $retval = array();
1228
1229 // Known row actions, in sort order
1230 $known_actions = $this->get_row_action_sort_order();
1231
1232 // Sort known actions, and keep any unknown ones
1233 foreach ( $known_actions as $key ) {
1234 if ( isset( $actions[ $key ] ) ) {
1235 $retval[ $key ] = $actions[ $key ];
1236 unset( $actions[ $key ] );
1237 }
1238 }
1239
1240 // Combine & return
1241 return $retval + $actions;
1242 }
1243
1244 /**
1245 * Add forum dropdown to topic and reply list table filters
1246 *
1247 * @since 2.0.0 bbPress (r3095)
1248 *
1249 * @return bool False. If post type is not topic or reply
1250 */
1251 public function filter_dropdown() {
1252
1253 // Get which forum is selected
1254 $selected = ! empty( $_GET['bbp_forum_id'] )
1255 ? (int) $_GET['bbp_forum_id']
1256 : 0;
1257
1258 // Show the forums dropdown
1259 bbp_dropdown(
1260 array(
1261 'selected' => $selected,
1262 'show_none' => esc_html__( 'In all forums', 'bbpress' )
1263 )
1264 );
1265 }
1266
1267 /**
1268 * Add "Empty Spam" button for moderators
1269 *
1270 * @since 2.6.0 bbPress (r6791)
1271 */
1272 public function filter_empty_spam() {
1273
1274 // Bail if not viewing spam
1275 if ( empty( $_GET['post_status'] ) || ( bbp_get_spam_status_id() !== $_GET['post_status'] ) && current_user_can( 'moderate' ) ) {
1276 return;
1277 }
1278
1279 ?>
1280
1281 <div class="alignleft actions"><?php
1282
1283 // Output the nonce & button
1284 wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
1285 submit_button(
1286 esc_attr__( 'Empty Spam', 'bbpress' ),
1287 'button-secondary apply',
1288 'delete_all',
1289 false
1290 );
1291
1292 ?></div><?php
1293 }
1294
1295 /**
1296 * Adjust the request query and include the forum id
1297 *
1298 * @since 2.0.0 bbPress (r3095)
1299 *
1300 * @param array $query_vars Query variables from {@link WP_Query}
1301 * @return array Processed Query Vars
1302 */
1303 public function filter_post_rows( $query_vars ) {
1304
1305 // Add post_parent query_var if one is present
1306 if ( ! empty( $_GET['bbp_forum_id'] ) ) {
1307 $query_vars['meta_key'] = '_bbp_forum_id';
1308 $query_vars['meta_type'] = 'NUMERIC';
1309 $query_vars['meta_value'] = (int) $_GET['bbp_forum_id'];
1310 }
1311
1312 // Return manipulated query_vars
1313 return $query_vars;
1314 }
1315
1316 /**
1317 * Custom user feedback messages for topic post type
1318 *
1319 * @since 2.0.0 bbPress (r3097)
1320 *
1321 * @global int $post_ID
1322 *
1323 * @param array $messages
1324 *
1325 * @return array
1326 */
1327 public function updated_messages( $messages ) {
1328 global $post_ID;
1329
1330 // URL for the current topic
1331 $topic_url = bbp_get_topic_permalink( $post_ID );
1332
1333 // Current topic's post_date
1334 $post_date = bbp_get_global_post_field( 'post_date', 'raw' );
1335
1336 // Messages array
1337 $messages[ $this->post_type ] = array(
1338 0 => '', // Left empty on purpose
1339
1340 // Updated
1341 1 => sprintf(
1342 '%1$s <a href="%2$s">%3$s</a>',
1343 esc_html__( 'Topic updated.', 'bbpress' ),
1344 $topic_url,
1345 esc_html__( 'View topic', 'bbpress' )
1346 ),
1347
1348 // Custom field updated
1349 2 => esc_html__( 'Custom field updated.', 'bbpress' ),
1350
1351 // Custom field deleted
1352 3 => esc_html__( 'Custom field deleted.', 'bbpress' ),
1353
1354 // Topic updated
1355 4 => esc_html__( 'Topic updated.', 'bbpress' ),
1356
1357 // Restored from revision
1358 /* translators: %s: date and time of the revision */
1359 5 => isset( $_GET['revision'] )
1360 /* translators: %s: Date and time of the revision */
1361 ? sprintf( esc_html__( 'Topic restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
1362 : false,
1363
1364 // Topic created
1365 6 => sprintf(
1366 '%1$s <a href="%2$s">%3$s</a>',
1367 esc_html__( 'Topic created.', 'bbpress' ),
1368 $topic_url,
1369 esc_html__( 'View topic', 'bbpress' )
1370 ),
1371
1372 // Topic saved
1373 7 => esc_html__( 'Topic saved.', 'bbpress' ),
1374
1375 // Topic submitted
1376 8 => sprintf(
1377 '%1$s <a href="%2$s" target="_blank">%3$s</a>',
1378 esc_html__( 'Topic submitted.', 'bbpress' ),
1379 esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
1380 esc_html__( 'Preview topic', 'bbpress' )
1381 ),
1382
1383 // Topic scheduled
1384 9 => sprintf(
1385 '%1$s <a target="_blank" href="%2$s">%3$s</a>',
1386 sprintf(
1387 /* translators: Publish box date format, see http://php.net/date */
1388 esc_html__( 'Topic scheduled for: %s.', 'bbpress' ),
1389 '<strong>' . date_i18n( __( 'M j, Y @ G:i', 'bbpress' ), strtotime( $post_date ) ) . '</strong>'
1390 ),
1391 $topic_url,
1392 esc_html__( 'Preview topic', 'bbpress' )
1393 ),
1394
1395 // Topic draft updated
1396 10 => sprintf(
1397 '%1$s <a href="%2$s" target="_blank">%3$s</a>',
1398 esc_html__( 'Topic draft updated.', 'bbpress' ),
1399 esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
1400 esc_html__( 'Preview topic', 'bbpress' )
1401 ),
1402 );
1403
1404 return $messages;
1405 }
1406 }
1407 endif; // class_exists check
1408
1409 /**
1410 * Setup bbPress Topics Admin
1411 *
1412 * This is currently here to make hooking and unhooking of the admin UI easy.
1413 * It could use dependency injection in the future, but for now this is easier.
1414 *
1415 * @since 2.0.0 bbPress (r3343)
1416 *
1417 * @param WP_Screen $current_screen Current screen object
1418 */
1419 function bbp_admin_topics( $current_screen ) {
1420
1421 // Bail if not in site admin
1422 if ( ! is_blog_admin() ) {
1423 return;
1424 }
1425
1426 // Bail if not a forum screen
1427 if ( empty( $current_screen->post_type ) || ( bbp_get_topic_post_type() !== $current_screen->post_type ) ) {
1428 return;
1429 }
1430
1431 // Init the topics admin
1432 bbp_admin()->topics = new BBP_Topics_Admin();
1433 }
1434