Skip to:
Content

bbPress.org

Changeset 7963


Ignore:
Timestamp:
10/11/2026 06:30:49 PM (12 days ago)
Author:
johnjamesjacoby
Message:

Forums: Keep closed content editable.

Treat closed topics and forums as closed to new content without freezing existing edits. Keep closed topics publicly readable, preserve normal edit locks and capabilities across theme compatibility, REST, XML-RPC, and custom integrations, and keep other closed forums unavailable as move destinations.

Merges [7962] to the 2.6 branch.

In branches/2.6, for 2.6.20.

See #3680.

Location:
branches/2.6
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • branches/2.6/CHANGELOG.md

    r7961 r7963  
    2929### Fixed
    3030
     31- Allowed authors to edit existing topics and replies after their topic or
     32  forum is closed and kept closed topics publicly readable, preserving the
     33  established new-content meaning of closing.
    3134- Allowed multilingual plugins to filter Recent Topics widget queries for all forums.
    3235- Handled malformed and numeric topic-view identifiers without PHP errors or
  • branches/2.6/src/includes/common/classes.php

    r7661 r7963  
    226226                                && ( bbp_get_forum_post_type() === $object->post_type )
    227227                                && ( bbp_is_forum_category( $object->ID )
    228                                         || ( ! current_user_can( 'edit_forum', $object->ID ) && bbp_is_forum_closed( $object->ID )
     228                                        || ( ! current_user_can( 'edit_forum', $object->ID )
     229                                                && bbp_is_forum_closed( $object->ID )
     230                                                && ( ! bbp_is_topic_edit() || ( (int) bbp_get_topic_forum_id() !== (int) $object->ID ) )
    229231                                )
    230232                        ) ) {
  • branches/2.6/src/includes/common/rest.php

    r7854 r7963  
    120120                }
    121121
    122                 // Match the front-end topic edit checks for category and closed forums.
     122                // Match the front-end topic edit check for category forums.
    123123                if ( ! empty( $post ) && ( bbp_get_topic_post_type() === $post->post_type ) ) {
    124124                        $topic_forum_id = bbp_get_topic_forum_id( $post->ID );
    125125
    126                         if ( bbp_is_forum_category( $topic_forum_id ) || ( bbp_is_forum_closed( $topic_forum_id ) && ! current_user_can( 'edit_forum', $topic_forum_id ) ) ) {
     126                        if ( bbp_is_forum_category( $topic_forum_id ) ) {
    127127                                return new WP_Error(
    128128                                        'bbp_rest_cannot_edit_topic_forum',
  • branches/2.6/src/includes/common/xmlrpc.php

    r7854 r7963  
    161161                if ( empty( $post_parent ) || bbp_is_forum_category( $post_parent ) ) {
    162162                        $invalid = true;
    163                 } elseif ( ! current_user_can( 'edit_forum', $post_parent ) && bbp_is_forum_closed( $post_parent ) ) {
     163                } elseif ( $parent_changed && ! current_user_can( 'edit_forum', $post_parent ) && bbp_is_forum_closed( $post_parent ) ) {
    164164                        $invalid = true;
    165165                } elseif ( ! current_user_can( 'read_forum', $post_parent ) ) {
  • branches/2.6/src/includes/topics/capabilities.php

    r7854 r7963  
    108108
    109109                                        // Post is public
    110                                         if ( bbp_get_public_status_id() === $_post->post_status ) {
     110                                        if ( in_array( $_post->post_status, bbp_get_public_topic_statuses(), true ) ) {
    111111
    112112                                                // Anonymous users do not have caps, but can 'exist'
  • branches/2.6/tests/phpunit/testcases/common/rest.php

    r7854 r7963  
    905905
    906906        /**
    907          * Topic edits through REST must honor the destination forum's type and status.
    908          *
    909          * @covers BBP_REST_Posts_Controller::update_item_permissions_check
    910          */
    911         public function test_participant_cannot_edit_topic_in_closed_or_category_forum_through_rest() {
     907         * Closing content prevents new content without freezing existing edits.
     908         *
     909         * @covers BBP_REST_Posts_Controller::update_item_permissions_check
     910         */
     911        public function test_participant_can_edit_topic_and_reply_in_closed_forum_through_rest() {
     912                $topic_owner_id = $this->factory->user->create();
     913                $reply_owner_id = $this->factory->user->create();
     914                $forum_id       = $this->factory->forum->create();
     915                $topic_id       = $this->factory->topic->create( array( 'post_author' => $topic_owner_id, 'post_parent' => $forum_id, 'post_content' => 'Original content.', 'topic_meta' => array( 'forum_id' => $forum_id ) ) );
     916                $reply_id       = $this->factory->reply->create( array( 'post_author' => $reply_owner_id, 'post_parent' => $topic_id, 'post_content' => 'Original reply.', 'reply_meta' => array( 'forum_id' => $forum_id, 'topic_id' => $topic_id ) ) );
     917
     918                bbp_set_user_role( $topic_owner_id, bbp_get_participant_role() );
     919                bbp_set_user_role( $reply_owner_id, bbp_get_participant_role() );
     920                bbp_close_topic( $topic_id );
     921                bbp_close_forum( $forum_id );
     922
     923                $response = $this->update_item( bbp_get_topic_post_type(), $topic_id, $topic_owner_id, array( 'content' => 'REST edit.' ) );
     924
     925                $this->assertSame( 200, $response->get_status() );
     926                $this->assertSame( 'REST edit.', get_post_field( 'post_content', $topic_id ) );
     927
     928                $response = $this->update_item( bbp_get_reply_post_type(), $reply_id, $reply_owner_id, array( 'content' => 'REST reply edit.' ) );
     929
     930                $this->assertSame( 200, $response->get_status() );
     931                $this->assertSame( 'REST reply edit.', get_post_field( 'post_content', $reply_id ) );
     932        }
     933
     934        /**
     935         * Topics cannot be edited while their parent is a category.
     936         *
     937         * @covers BBP_REST_Posts_Controller::update_item_permissions_check
     938         */
     939        public function test_participant_cannot_edit_topic_in_category_forum_through_rest() {
    912940                $user_id  = $this->factory->user->create();
    913941                $forum_id = $this->factory->forum->create();
    … …  
    915943
    916944                bbp_set_user_role( $user_id, bbp_get_participant_role() );
    917                 bbp_close_forum( $forum_id );
    918 
    919                 $response = $this->update_item( bbp_get_topic_post_type(), $topic_id, $user_id, array( 'content' => 'REST edit.' ) );
    920 
    921                 $this->assertSame( 403, $response->get_status() );
    922                 $this->assertSame( 'Original content.', get_post_field( 'post_content', $topic_id ) );
    923 
    924                 bbp_open_forum( $forum_id );
    925945                bbp_categorize_forum( $forum_id );
    926946
  • branches/2.6/tests/phpunit/testcases/common/xmlrpc.php

    r7854 r7963  
    658658         * @covers ::bbp_validate_xmlrpc_post
    659659         */
    660         public function test_participant_cannot_edit_topic_in_closed_forum() {
    661                 $user_id  = $this->create_participant();
    662                 $forum_id = $this->factory->forum->create(
     660        public function test_participant_can_edit_topic_and_reply_in_closed_forum() {
     661                $user_id        = $this->create_participant();
     662                $topic_owner_id = $this->factory->user->create( array( 'role' => bbp_get_participant_role() ) );
     663                $forum_id       = $this->factory->forum->create(
    663664                        array( 'forum_meta' => array( 'status' => 'closed' ) )
    664665                );
    … …  
    670671                        )
    671672                );
     673                $reply_topic_id = $this->factory->topic->create(
     674                        array(
     675                                'post_author' => $topic_owner_id,
     676                                'post_parent' => $forum_id,
     677                                'topic_meta'  => array( 'forum_id' => $forum_id ),
     678                        )
     679                );
     680                $reply_id = $this->factory->reply->create(
     681                        array(
     682                                'post_author' => $user_id,
     683                                'post_parent' => $reply_topic_id,
     684                                'reply_meta'  => array(
     685                                        'forum_id' => $forum_id,
     686                                        'topic_id' => $reply_topic_id,
     687                                ),
     688                        )
     689                );
     690
     691                bbp_close_topic( $topic_id );
     692                bbp_close_topic( $reply_topic_id );
    672693
    673694                $result = $this->edit_post( $topic_id, array( 'post_content' => 'Updated topic content.' ) );
    674695
    675                 $this->assertInstanceOf( 'IXR_Error', $result );
    676                 $this->assertNotSame( 'Updated topic content.', get_post_field( 'post_content', $topic_id ) );
     696                $this->assertNotInstanceOf( 'IXR_Error', $result );
     697                $this->assertSame( 'Updated topic content.', get_post_field( 'post_content', $topic_id ) );
     698
     699                $result = $this->edit_post( $reply_id, array( 'post_content' => 'Updated reply content.' ) );
     700
     701                $this->assertNotInstanceOf( 'IXR_Error', $result );
     702                $this->assertSame( 'Updated reply content.', get_post_field( 'post_content', $reply_id ) );
    677703        }
    678704
  • branches/2.6/tests/phpunit/testcases/replies/functions/permissions.php

    r7854 r7963  
    167167        }
    168168
     169        /**
     170         * @covers ::bbp_edit_reply_handler
     171         */
     172        public function test_participant_can_edit_own_reply_in_closed_topic_and_forum_theme_side() {
     173                $user_id  = $this->factory->user->create( array( 'role' => bbp_get_participant_role() ) );
     174                $forum_id = $this->factory->forum->create();
     175                $topic_id = $this->factory->topic->create(
     176                        array(
     177                                'post_parent' => $forum_id,
     178                                'topic_meta'  => array( 'forum_id' => $forum_id ),
     179                        )
     180                );
     181                $reply_id = $this->factory->reply->create(
     182                        array(
     183                                'post_author' => $user_id,
     184                                'post_parent' => $topic_id,
     185                                'reply_meta'  => array(
     186                                        'forum_id' => $forum_id,
     187                                        'topic_id' => $topic_id,
     188                                ),
     189                        )
     190                );
     191
     192                bbp_close_topic( $topic_id );
     193                bbp_close_forum( $forum_id );
     194                $this->set_current_user( $user_id );
     195                bbpress()->errors = new WP_Error();
     196
     197                $did_redirect = $this->submit_reply_edit( $reply_id, 'Participant reply edit in closed content.' );
     198
     199                $this->assertSame( array(), bbpress()->errors->get_error_codes() );
     200                $this->assertSame( 'Participant reply edit in closed content.', get_post_field( 'post_content', $reply_id ) );
     201                $this->assertTrue( $did_redirect );
     202        }
     203
    169204        protected function submit_reply_move( $reply_id, $move_option, $destination_topic_id = 0, $destination_title = null ) {
    170205                $home_url             = wp_parse_url( home_url( '/' ) );
  • branches/2.6/tests/phpunit/testcases/topics/functions/permissions.php

    r7854 r7963  
    3535                parent::tearDown();
    3636        }
     37
     38        protected function submit_topic_edit( $topic_id, $forum_id, $content ) {
     39                $home_url             = wp_parse_url( home_url( '/' ) );
     40                $_SERVER['HTTP_HOST'] = $home_url['host'];
     41
     42                if ( isset( $home_url['port'] ) ) {
     43                        $_SERVER['HTTP_HOST'] .= ':' . $home_url['port'];
     44                }
     45
     46                $_SERVER['REQUEST_URI']     = $home_url['path'];
     47                $_POST['bbp_topic_id']      = $topic_id;
     48                $_POST['bbp_forum_id']      = $forum_id;
     49                $_POST['bbp_topic_title']   = bbp_get_topic_title( $topic_id );
     50                $_POST['bbp_topic_content'] = $content;
     51                $_REQUEST['_wpnonce']       = wp_create_nonce( 'bbp-edit-topic_' . $topic_id );
     52
     53                $did_redirect     = false;
     54                $prevent_redirect = function() use ( &$did_redirect ) {
     55                        $did_redirect = true;
     56                        throw new RuntimeException( 'Topic edit redirect.' );
     57                };
     58
     59                add_filter( 'wp_redirect', $prevent_redirect );
     60
     61                try {
     62                        bbp_edit_topic_handler( 'bbp-edit-topic' );
     63                } catch ( RuntimeException $exception ) {
     64                        if ( 'Topic edit redirect.' !== $exception->getMessage() ) {
     65                                throw $exception;
     66                        }
     67                } finally {
     68                        remove_filter( 'wp_redirect', $prevent_redirect );
     69                }
     70
     71                return $did_redirect;
     72        }
     73
     74        /**
     75         * @covers ::bbp_edit_topic_handler
     76         */
     77        public function test_participant_can_edit_own_closed_topic_in_closed_forum_theme_side() {
     78                $user_id  = $this->factory->user->create( array( 'role' => bbp_get_participant_role() ) );
     79                $forum_id = $this->factory->forum->create();
     80                $topic_id = $this->factory->topic->create(
     81                        array(
     82                                'post_author' => $user_id,
     83                                'post_parent' => $forum_id,
     84                                'topic_meta'  => array( 'forum_id' => $forum_id ),
     85                        )
     86                );
     87
     88                bbp_close_topic( $topic_id );
     89                bbp_close_forum( $forum_id );
     90                $this->set_current_user( $user_id );
     91                bbpress()->errors = new WP_Error();
     92
     93                $this->assertTrue( current_user_can( 'edit_topic', $topic_id ) );
     94                $this->assertFalse( current_user_can( 'edit_forum', $forum_id ) );
     95
     96                $did_redirect = $this->submit_topic_edit( $topic_id, $forum_id, 'Participant edit in closed content.' );
     97
     98                $this->assertSame( array(), bbpress()->errors->get_error_codes() );
     99                $this->assertSame( 'Participant edit in closed content.', get_post_field( 'post_content', $topic_id ) );
     100                $this->assertTrue( $did_redirect );
     101        }
     102
     103        /**
     104         * @covers ::bbp_edit_topic_handler
     105         */
     106        public function test_forum_moderator_can_edit_closed_topic_in_closed_forum_theme_side() {
     107                $user_id        = $this->factory->user->create( array( 'role' => bbp_get_participant_role() ) );
     108                $topic_owner_id = $this->factory->user->create( array( 'role' => bbp_get_participant_role() ) );
     109                $forum_id       = $this->factory->forum->create();
     110                $topic_id       = $this->factory->topic->create(
     111                        array(
     112                                'post_author' => $topic_owner_id,
     113                                'post_parent' => $forum_id,
     114                                'topic_meta'  => array( 'forum_id' => $forum_id ),
     115                        )
     116                );
     117
     118                bbp_add_moderator( $forum_id, $user_id );
     119                bbp_close_topic( $topic_id );
     120                bbp_close_forum( $forum_id );
     121                $this->set_current_user( $user_id );
     122                bbpress()->errors = new WP_Error();
     123
     124                $this->assertTrue( current_user_can( 'moderate', $topic_id ) );
     125                $this->assertTrue( current_user_can( 'edit_forum', $forum_id ) );
     126
     127                $did_redirect = $this->submit_topic_edit( $topic_id, $forum_id, 'Forum moderator edit in closed content.' );
     128
     129                $this->assertSame( array(), bbpress()->errors->get_error_codes() );
     130                $this->assertSame( 'Forum moderator edit in closed content.', get_post_field( 'post_content', $topic_id ) );
     131                $this->assertTrue( $did_redirect );
     132        }
     133
     134        /**
     135         * @covers ::bbp_edit_topic_handler
     136         */
     137        public function test_forum_moderator_cannot_move_topic_to_closed_forum() {
     138                $user_id         = $this->factory->user->create( array( 'role' => bbp_get_participant_role() ) );
     139                $topic_owner_id  = $this->factory->user->create( array( 'role' => bbp_get_participant_role() ) );
     140                $source_forum_id = $this->factory->forum->create();
     141                $closed_forum_id = $this->factory->forum->create();
     142                $topic_id        = $this->factory->topic->create(
     143                        array(
     144                                'post_author' => $topic_owner_id,
     145                                'post_parent' => $source_forum_id,
     146                                'topic_meta'  => array( 'forum_id' => $source_forum_id ),
     147                        )
     148                );
     149
     150                bbp_add_moderator( $source_forum_id, $user_id );
     151                bbp_close_forum( $closed_forum_id );
     152                $this->set_current_user( $user_id );
     153                bbpress()->errors = new WP_Error();
     154
     155                $this->assertTrue( current_user_can( 'edit_forum', $source_forum_id ) );
     156                $this->assertFalse( current_user_can( 'edit_forum', $closed_forum_id ) );
     157
     158                $did_redirect = $this->submit_topic_edit( $topic_id, $closed_forum_id, 'Move to closed forum.' );
     159
     160                $this->assertContains( 'bbp_edit_topic_forum_closed', bbpress()->errors->get_error_codes() );
     161                $this->assertSame( $source_forum_id, bbp_get_topic_forum_id( $topic_id ) );
     162                $this->assertFalse( $did_redirect );
     163        }
     164
    37165
    38166        /**
Note: See TracChangeset for help on using the changeset viewer.