| @@ -15,9 +15,9 @@ | ||
| 15 | 15 | * Loads bbPress replies admin area |
| 16 | 16 | * |
| 17 | 17 | * @package bbPress |
| 18 | 18 | * @subpackage Administration |
| 19 | - * @since 2.0.0 bbPress (r2464) | |
| 19 | + * @since 2.0.0 bbPress (r3095) | |
| 20 | 20 | */ |
| 21 | 21 | class BBP_Replies_Admin { |
| 22 | 22 | |
| 23 | 23 | /** Variables *************************************************************/ |
| @@ -26,14 +26,16 @@ | ||
| 26 | 26 | * @var The post type of this admin component |
| 27 | 27 | */ |
| 28 | 28 | private $post_type = ''; |
| 29 | 29 | |
| 30 | + private $accepted_topic_moves = array(); | |
| 31 | + | |
| 30 | 32 | /** Functions *************************************************************/ |
| 31 | 33 | |
| 32 | 34 | /** |
| 33 | 35 | * The main bbPress admin loader |
| 34 | 36 | * |
| 35 | - * @since 2.0.0 bbPress (r2515) | |
| 37 | + * @since 2.0.0 bbPress (r3095) | |
| 36 | 38 | */ |
| 37 | 39 | public function __construct() { |
| 38 | 40 | $this->setup_globals(); |
| 39 | 41 | $this->setup_actions(); |
| @@ -41,9 +43,9 @@ | ||
| 41 | 43 | |
| 42 | 44 | /** |
| 43 | 45 | * Setup the admin hooks, actions and filters |
| 44 | 46 | * |
| 45 | - * @since 2.0.0 bbPress (r2646) | |
| 47 | + * @since 2.0.0 bbPress (r3376) | |
| 46 | 48 | * @since 2.6.0 bbPress (r6101) Added bulk actions |
| 47 | 49 | * |
| 48 | 50 | * @access private |
| 49 | 51 | */ |
| @@ -70,8 +72,9 @@ | ||
| 70 | 72 | add_action( 'add_meta_boxes', array( $this, 'attributes_metabox' ) ); |
| 71 | 73 | add_action( 'add_meta_boxes', array( $this, 'author_metabox' ) ); |
| 72 | 74 | add_action( 'add_meta_boxes', array( $this, 'comments_metabox' ) ); |
| 73 | 75 | add_action( 'save_post', array( $this, 'save_meta_boxes' ) ); |
| 76 | + add_filter( 'wp_insert_post_data', array( $this, 'filter_post_data' ), 20, 2 ); | |
| 74 | 77 | |
| 75 | 78 | // Check if there are any bbp_toggle_reply_* requests on admin_init, also have a message displayed |
| 76 | 79 | add_action( 'load-edit.php', array( $this, 'toggle_reply' ) ); |
| 77 | 80 | add_action( 'load-edit.php', array( $this, 'toggle_reply_notice' ) ); |
| @@ -91,9 +94,9 @@ | ||
| 91 | 94 | |
| 92 | 95 | /** |
| 93 | 96 | * Admin globals |
| 94 | 97 | * |
| 95 | - * @since 2.0.0 bbPress (r2646) | |
| 98 | + * @since 2.0.0 bbPress (r3376) | |
| 96 | 99 | * |
| 97 | 100 | * @access private |
| 98 | 101 | */ |
| 99 | 102 | private function setup_globals() { |
| @@ -104,9 +107,9 @@ | ||
| 104 | 107 | |
| 105 | 108 | /** |
| 106 | 109 | * Contextual help for bbPress reply edit page |
| 107 | 110 | * |
| 108 | - * @since 2.0.0 bbPress (r3119) | |
| 111 | + * @since 2.1.0 bbPress (r3686) | |
| 109 | 112 | */ |
| 110 | 113 | public function edit_help() { |
| 111 | 114 | |
| 112 | 115 | // Overview |
| @@ -174,9 +177,9 @@ | ||
| 174 | 177 | |
| 175 | 178 | /** |
| 176 | 179 | * Contextual help for bbPress reply edit page |
| 177 | 180 | * |
| 178 | - * @since 2.0.0 bbPress (r3119) | |
| 181 | + * @since 2.1.0 bbPress (r3686) | |
| 179 | 182 | */ |
| 180 | 183 | public function new_help() { |
| 181 | 184 | |
| 182 | 185 | $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>'; |
| @@ -351,9 +354,9 @@ | ||
| 351 | 354 | |
| 352 | 355 | /** |
| 353 | 356 | * Add the reply attributes meta-box |
| 354 | 357 | * |
| 355 | - * @since 2.0.0 bbPress (r2746) | |
| 358 | + * @since 2.4.0 bbPress (r4991) | |
| 356 | 359 | */ |
| 357 | 360 | public function attributes_metabox() { |
| 358 | 361 | add_meta_box( |
| 359 | 362 | 'bbp_reply_attributes', |
| @@ -369,9 +372,9 @@ | ||
| 369 | 372 | * Add the author info meta-box |
| 370 | 373 | * |
| 371 | 374 | * Allows editing of information about an author |
| 372 | 375 | * |
| 373 | - * @since 2.0.0 bbPress (r2828) | |
| 376 | + * @since 2.0.0 bbPress (r3120) | |
| 374 | 377 | */ |
| 375 | 378 | public function author_metabox() { |
| 376 | 379 | |
| 377 | 380 | // Bail if post_type is not a reply |
| @@ -404,15 +407,24 @@ | ||
| 404 | 407 | |
| 405 | 408 | /** |
| 406 | 409 | * Pass the reply attributes for processing |
| 407 | 410 | * |
| 408 | - * @since 2.0.0 bbPress (r2746) | |
| 411 | + * @since 2.6.0 bbPress (r6056) | |
| 409 | 412 | * |
| 410 | 413 | * @param int $reply_id Reply id |
| 411 | 414 | * @return int Parent id |
| 412 | 415 | */ |
| 413 | 416 | public function save_meta_boxes( $reply_id ) { |
| 417 | + $accepted_move = isset( $this->accepted_topic_moves[ $reply_id ] ) | |
| 418 | + ? $this->accepted_topic_moves[ $reply_id ] | |
| 419 | + : array(); | |
| 420 | + unset( $this->accepted_topic_moves[ $reply_id ] ); | |
| 414 | 421 | |
| 422 | + // Revisions can also fire save_post with the metabox nonce. | |
| 423 | + if ( ! bbp_is_reply( $reply_id ) ) { | |
| 424 | + return $reply_id; | |
| 425 | + } | |
| 426 | + | |
| 415 | 427 | // Bail if doing an autosave |
| 416 | 428 | if ( bbp_doing_autosave() ) { |
| 417 | 429 | return $reply_id; |
| 418 | 430 | } |
| @@ -432,16 +444,21 @@ | ||
| 432 | 444 | return $reply_id; |
| 433 | 445 | } |
| 434 | 446 | |
| 435 | 447 | // Bail if current user cannot edit this reply |
| 436 | - if ( ! current_user_can( 'edit_reply', $reply_id ) ) { | |
| 448 | + if ( ! current_user_can( 'edit_reply', $reply_id ) && empty( $accepted_move ) ) { | |
| 437 | 449 | return $reply_id; |
| 438 | 450 | } |
| 439 | 451 | |
| 440 | - // Get the reply meta post values | |
| 441 | - $topic_id = ! empty( $_POST['parent_id'] ) ? (int) $_POST['parent_id'] : 0; | |
| 442 | - $forum_id = ! empty( $_POST['bbp_forum_id'] ) ? (int) $_POST['bbp_forum_id'] : bbp_get_topic_forum_id( $topic_id ); | |
| 443 | - $reply_to = ! empty( $_POST['bbp_reply_to'] ) ? (int) $_POST['bbp_reply_to'] : 0; | |
| 452 | + // Use the accepted topic and its forum, rather than independent form values. | |
| 453 | + $topic_id = ! empty( $accepted_move ) | |
| 454 | + ? $accepted_move['new'] | |
| 455 | + : bbp_get_reply_topic_id( $reply_id ); | |
| 456 | + $forum_id = bbp_get_topic_forum_id( $topic_id ); | |
| 457 | + $reply_to = ! empty( $_POST['bbp_reply_to'] ) ? bbp_validate_reply_to( (int) $_POST['bbp_reply_to'], $reply_id ) : 0; | |
| 458 | + if ( ! empty( $reply_to ) && ( bbp_get_reply_topic_id( $reply_to ) !== $topic_id || ! current_user_can( 'read_reply', $reply_to ) ) ) { | |
| 459 | + $reply_to = 0; | |
| 460 | + } | |
| 444 | 461 | |
| 445 | 462 | // Get reply author data |
| 446 | 463 | $anonymous_data = bbp_filter_anonymous_post_data(); |
| 447 | 464 | $author_id = bbp_get_reply_author_id( $reply_id ); |
| @@ -448,8 +465,12 @@ | ||
| 448 | 465 | $is_edit = ( isset( $_POST['hidden_post_status'] ) && ( 'draft' !== $_POST['hidden_post_status'] ) ); |
| 449 | 466 | |
| 450 | 467 | // Formally update the reply |
| 451 | 468 | bbp_update_reply( $reply_id, $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit, $reply_to ); |
| 469 | + if ( ! empty( $accepted_move['old'] ) ) { | |
| 470 | + bbp_update_reply_position( $reply_id ); | |
| 471 | + bbp_move_reply_count( $reply_id, $accepted_move['old'], $accepted_move['new'] ); | |
| 472 | + } | |
| 452 | 473 | |
| 453 | 474 | // Allow other fun things to happen |
| 454 | 475 | do_action( 'bbp_reply_attributes_metabox_save', $reply_id, $topic_id, $forum_id, $reply_to ); |
| 455 | 476 | do_action( 'bbp_author_metabox_save', $reply_id, $anonymous_data ); |
| @@ -457,13 +478,82 @@ | ||
| 457 | 478 | return $reply_id; |
| 458 | 479 | } |
| 459 | 480 | |
| 460 | 481 | /** |
| 482 | + * Keep admin reply moves within topics the current user may moderate. | |
| 483 | + * | |
| 484 | + * @since 2.6.19 bbPress (r7688) | |
| 485 | + * | |
| 486 | + * @param array $data Sanitized post data. | |
| 487 | + * @param array $postarr Unprocessed post data. | |
| 488 | + * @return array Filtered post data. | |
| 489 | + */ | |
| 490 | + public function filter_post_data( $data, $postarr ) { | |
| 491 | + | |
| 492 | + // Only filter administration saves of existing replies. | |
| 493 | + if ( ! is_admin() || empty( $postarr['ID'] ) || ( bbp_get_reply_post_type() !== $data['post_type'] ) ) { | |
| 494 | + return $data; | |
| 495 | + } | |
| 496 | + | |
| 497 | + $reply = bbp_get_reply( $postarr['ID'] ); | |
| 498 | + if ( empty( $reply ) || (int) $reply->post_parent === (int) $data['post_parent'] ) { | |
| 499 | + return $data; | |
| 500 | + } | |
| 501 | + | |
| 502 | + $old_topic_id = (int) $reply->post_parent; | |
| 503 | + $new_topic_id = (int) $data['post_parent']; | |
| 504 | + $new_topic = bbp_get_topic( $new_topic_id ); | |
| 505 | + $new_forum_id = bbp_get_topic_forum_id( $new_topic_id ); | |
| 506 | + $is_new = ( 'auto-draft' === $reply->post_status ); | |
| 507 | + $is_editor = ! empty( $_POST['action'] ) && ( 'editpost' === $_POST['action'] ); | |
| 508 | + | |
| 509 | + // Other admin save paths cannot complete a bbPress reply move. | |
| 510 | + if ( ! $is_editor && ! $is_new ) { | |
| 511 | + $data['post_parent'] = $reply->post_parent; | |
| 512 | + return $data; | |
| 513 | + } | |
| 514 | + | |
| 515 | + // Match the reply move checks before WordPress changes post_parent. | |
| 516 | + if ( | |
| 517 | + ! $is_editor | |
| 518 | + || empty( $_POST['bbp_reply_metabox'] ) | |
| 519 | + || ! is_string( $_POST['bbp_reply_metabox'] ) | |
| 520 | + || ! wp_verify_nonce( $_POST['bbp_reply_metabox'], 'bbp_reply_metabox_save' ) | |
| 521 | + || ! current_user_can( 'edit_reply', $reply->ID ) | |
| 522 | + || ( $is_new && ! current_user_can( 'publish_replies' ) ) | |
| 523 | + || ( ! $is_new && ! empty( $old_topic_id ) && ( ! current_user_can( 'moderate', $old_topic_id ) || ! current_user_can( 'edit_topic', $old_topic_id ) ) ) | |
| 524 | + || empty( $new_topic ) | |
| 525 | + || ( $is_new && ( ! current_user_can( 'read_topic', $new_topic_id ) || ( bbp_is_topic_closed( $new_topic_id ) && ! current_user_can( 'edit_topic', $new_topic_id ) ) ) ) | |
| 526 | + || ( $is_new && ( ! current_user_can( 'read_forum', $new_forum_id ) || ( bbp_is_forum_closed( $new_forum_id ) && ! current_user_can( 'edit_forum', $new_forum_id ) ) ) ) | |
| 527 | + || ( ! $is_new && ( ! current_user_can( 'moderate', $new_topic_id ) || ! current_user_can( 'edit_topic', $new_topic_id ) ) ) | |
| 528 | + ) { | |
| 529 | + if ( $is_new ) { | |
| 530 | + wp_die( | |
| 531 | + esc_html__( 'The selected topic is not available for this reply.', 'bbpress' ), | |
| 532 | + '', | |
| 533 | + array( | |
| 534 | + 'response' => 403, | |
| 535 | + 'back_link' => true, | |
| 536 | + ) | |
| 537 | + ); | |
| 538 | + } | |
| 539 | + $data['post_parent'] = $reply->post_parent; | |
| 540 | + } else { | |
| 541 | + $this->accepted_topic_moves[ $reply->ID ] = array( | |
| 542 | + 'old' => $old_topic_id, | |
| 543 | + 'new' => $new_topic_id, | |
| 544 | + ); | |
| 545 | + } | |
| 546 | + | |
| 547 | + return $data; | |
| 548 | + } | |
| 549 | + | |
| 550 | + /** | |
| 461 | 551 | * Toggle reply |
| 462 | 552 | * |
| 463 | 553 | * Handles the admin-side spamming/unspamming of replies |
| 464 | 554 | * |
| 465 | - * @since 2.0.0 bbPress (r2740) | |
| 555 | + * @since 2.0.0 bbPress (r3095) | |
| 466 | 556 | */ |
| 467 | 557 | public function toggle_reply() { |
| 468 | 558 | |
| 469 | 559 | // Bail if not a topic toggle action |
| @@ -548,9 +638,9 @@ | ||
| 548 | 638 | * |
| 549 | 639 | * Display the success/error notices from |
| 550 | 640 | * {@link BBP_Admin::toggle_reply()} |
| 551 | 641 | * |
| 552 | - * @since 2.0.0 bbPress (r2740) | |
| 642 | + * @since 2.0.0 bbPress (r3095) | |
| 553 | 643 | */ |
| 554 | 644 | public function toggle_reply_notice() { |
| 555 | 645 | |
| 556 | 646 | // Bail if missing reply toggle action |
| @@ -626,9 +716,9 @@ | ||
| 626 | 716 | |
| 627 | 717 | /** |
| 628 | 718 | * Returns an array of keys used to sort row actions |
| 629 | 719 | * |
| 630 | - * @since 2.6.0 bbPress (r6771) | |
| 720 | + * @since 2.6.0 bbPress (r6772) | |
| 631 | 721 | * |
| 632 | 722 | * @return array |
| 633 | 723 | */ |
| 634 | 724 | private function get_row_action_sort_order() { |
| @@ -635,9 +725,9 @@ | ||
| 635 | 725 | |
| 636 | 726 | /** |
| 637 | 727 | * Filters the row action sort order for replies. |
| 638 | 728 | * |
| 639 | - * @since 2.6.0 bbPress (r6771) | |
| 729 | + * @since 2.6.0 bbPress (r6772) | |
| 640 | 730 | * |
| 641 | 731 | * @param array $order The default sort order. |
| 642 | 732 | */ |
| 643 | 733 | return (array) apply_filters( |
| @@ -658,9 +748,9 @@ | ||
| 658 | 748 | |
| 659 | 749 | /** |
| 660 | 750 | * Returns an array of notice toggles |
| 661 | 751 | * |
| 662 | - * @since 2.6.0 bbPress (r6396) | |
| 752 | + * @since 2.6.0 bbPress (r6397) | |
| 663 | 753 | * |
| 664 | 754 | * @return array |
| 665 | 755 | */ |
| 666 | 756 | private function get_allowed_notice_toggles() { |
| @@ -679,9 +769,9 @@ | ||
| 679 | 769 | |
| 680 | 770 | /** |
| 681 | 771 | * Returns an array of notice toggles |
| 682 | 772 | * |
| 683 | - * @since 2.6.0 bbPress (r6396) | |
| 773 | + * @since 2.6.0 bbPress (r6397) | |
| 684 | 774 | * |
| 685 | 775 | * @return array |
| 686 | 776 | */ |
| 687 | 777 | private function get_allowed_action_toggles() { |
| @@ -698,9 +788,9 @@ | ||
| 698 | 788 | |
| 699 | 789 | /** |
| 700 | 790 | * Manage the column headers for the replies page |
| 701 | 791 | * |
| 702 | - * @since 2.0.0 bbPress (r2577) | |
| 792 | + * @since 2.4.0 bbPress (r4991) | |
| 703 | 793 | * |
| 704 | 794 | * @param array $columns The columns |
| 705 | 795 | * |
| 706 | 796 | * @return array $columns bbPress reply columns |
| @@ -721,9 +811,9 @@ | ||
| 721 | 811 | |
| 722 | 812 | /** |
| 723 | 813 | * Print extra columns for the replies page |
| 724 | 814 | * |
| 725 | - * @since 2.0.0 bbPress (r2577) | |
| 815 | + * @since 2.4.0 bbPress (r4991) | |
| 726 | 816 | * |
| 727 | 817 | * @param string $column Column |
| 728 | 818 | * @param int $reply_id reply id |
| 729 | 819 | */ |
| @@ -818,9 +908,9 @@ | ||
| 818 | 908 | * |
| 819 | 909 | * Remove the quick-edit action link under the reply title and add the |
| 820 | 910 | * content and spam link |
| 821 | 911 | * |
| 822 | - * @since 2.0.0 bbPress (r2577) | |
| 912 | + * @since 2.4.0 bbPress (r4991) | |
| 823 | 913 | * |
| 824 | 914 | * @param array $actions Actions |
| 825 | 915 | * @param object $reply Reply object |
| 826 | 916 | * |
| @@ -910,9 +1000,9 @@ | ||
| 910 | 1000 | |
| 911 | 1001 | /** |
| 912 | 1002 | * Sort row actions by key |
| 913 | 1003 | * |
| 914 | - * @since 2.6.0 | |
| 1004 | + * @since 2.6.0 bbPress (r6772) | |
| 915 | 1005 | * |
| 916 | 1006 | * @param array $actions |
| 917 | 1007 | * |
| 918 | 1008 | * @return array |
| @@ -939,9 +1029,9 @@ | ||
| 939 | 1029 | |
| 940 | 1030 | /** |
| 941 | 1031 | * Add forum dropdown to topic and reply list table filters |
| 942 | 1032 | * |
| 943 | - * @since 2.0.0 bbPress (r2991) | |
| 1033 | + * @since 2.0.0 bbPress (r3095) | |
| 944 | 1034 | * |
| 945 | 1035 | * @return bool False. If post type is not topic or reply |
| 946 | 1036 | */ |
| 947 | 1037 | public function filter_dropdown() { |
| @@ -990,9 +1080,9 @@ | ||
| 990 | 1080 | |
| 991 | 1081 | /** |
| 992 | 1082 | * Adjust the request query and include the forum id |
| 993 | 1083 | * |
| 994 | - * @since 2.0.0 bbPress (r2991) | |
| 1084 | + * @since 2.0.0 bbPress (r3095) | |
| 995 | 1085 | * |
| 996 | 1086 | * @param array $query_vars Query variables from {@link WP_Query} |
| 997 | 1087 | * @return array Processed Query Vars |
| 998 | 1088 | */ |
| @@ -1011,9 +1101,9 @@ | ||
| 1011 | 1101 | |
| 1012 | 1102 | /** |
| 1013 | 1103 | * Custom user feedback messages for reply post type |
| 1014 | 1104 | * |
| 1015 | - * @since 2.0.0 bbPress (r3080) | |
| 1105 | + * @since 2.0.0 bbPress (r3097) | |
| 1016 | 1106 | * |
| 1017 | 1107 | * @global int $post_ID |
| 1018 | 1108 | * |
| 1019 | 1109 | * @param array $messages |
| @@ -1107,13 +1197,18 @@ | ||
| 1107 | 1197 | * |
| 1108 | 1198 | * This is currently here to make hooking and unhooking of the admin UI easy. |
| 1109 | 1199 | * It could use dependency injection in the future, but for now this is easier. |
| 1110 | 1200 | * |
| 1111 | - * @since 2.0.0 bbPress (r2596) | |
| 1201 | + * @since 2.0.0 bbPress (r3343) | |
| 1112 | 1202 | * |
| 1113 | 1203 | * @param WP_Screen $current_screen Current screen object |
| 1114 | 1204 | */ |
| 1115 | 1205 | function bbp_admin_replies( $current_screen ) { |
| 1206 | + | |
| 1207 | + // Bail if not in site admin | |
| 1208 | + if ( ! is_blog_admin() ) { | |
| 1209 | + return; | |
| 1210 | + } | |
| 1116 | 1211 | |
| 1117 | 1212 | // Bail if not a forum screen |
| 1118 | 1213 | if ( empty( $current_screen->post_type ) || ( bbp_get_reply_post_type() !== $current_screen->post_type ) ) { |
| 1119 | 1214 | return; |