diff --git a/src/js/_enqueues/admin/post.js b/src/js/_enqueues/admin/post.js index 1c166a82cb32a..f9ed69feecc7d 100644 --- a/src/js/_enqueues/admin/post.js +++ b/src/js/_enqueues/admin/post.js @@ -738,8 +738,8 @@ jQuery( function($) { * @return {void} */ updateVisibility = function() { - // Show sticky for public posts. - if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) { + // Show sticky for public and password protected posts. + if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) { $('#sticky').prop('checked', false); $('#sticky-span').hide(); } else { @@ -907,7 +907,7 @@ jQuery( function($) { $('#visibility .edit-visibility').show().trigger( 'focus' ); updateText(); - if ( 'public' !== selectedVisibility ) { + if ( 'private' === selectedVisibility ) { $('#sticky').prop('checked', false); } @@ -919,7 +919,7 @@ jQuery( function($) { visibilityLabel = __( 'Private' ); break; case 'password': - visibilityLabel = __( 'Password Protected' ); + visibilityLabel = $( '#sticky' ).prop( 'checked' ) ? __( 'Password protected, Sticky' ) : __( 'Password Protected' ); break; } diff --git a/src/wp-admin/includes/meta-boxes.php b/src/wp-admin/includes/meta-boxes.php index 9149f50daadd8..75179f3591b42 100644 --- a/src/wp-admin/includes/meta-boxes.php +++ b/src/wp-admin/includes/meta-boxes.php @@ -180,7 +180,7 @@ function post_submit_meta_box( $post, $args = array() ) { $visibility_trans = __( 'Private' ); } elseif ( ! empty( $post->post_password ) ) { $visibility = 'password'; - $visibility_trans = __( 'Password protected' ); + $visibility_trans = ( 'post' === $post_type && is_sticky( $post_id ) ) ? __( 'Password protected, Sticky' ) : __( 'Password protected' ); } elseif ( 'post' === $post_type && is_sticky( $post_id ) ) { $visibility = 'public'; $visibility_trans = __( 'Public, Sticky' ); diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index a255673aad601..d5250db4d84b9 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -320,9 +320,6 @@ function edit_post( $post_data = null ) { case 'public': $post_data['post_password'] = ''; break; - case 'password': - unset( $post_data['sticky'] ); - break; case 'private': $post_data['post_status'] = 'private'; $post_data['post_password'] = ''; @@ -952,9 +949,6 @@ function wp_write_post() { case 'public': $_POST['post_password'] = ''; break; - case 'password': - unset( $_POST['sticky'] ); - break; case 'private': $_POST['post_status'] = 'private'; $_POST['post_password'] = ''; diff --git a/src/wp-includes/class-wp-xmlrpc-server.php b/src/wp-includes/class-wp-xmlrpc-server.php index 4ac680065f036..472c5a6f9f926 100644 --- a/src/wp-includes/class-wp-xmlrpc-server.php +++ b/src/wp-includes/class-wp-xmlrpc-server.php @@ -1431,8 +1431,8 @@ private function _is_greater_than_one( $count ) { private function _toggle_sticky( $post_data, $update = false ) { $post_type = get_post_type_object( $post_data['post_type'] ); - // Private and password-protected posts cannot be stickied. - if ( 'private' === $post_data['post_status'] || ! empty( $post_data['post_password'] ) ) { + // Private posts cannot be stickied. + if ( 'private' === $post_data['post_status'] ) { // Error if the client tried to stick the post, otherwise, silently unstick. if ( ! empty( $post_data['sticky'] ) ) { return new IXR_Error( 401, __( 'Sorry, you cannot stick a private post.' ) ); diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index 0c24925ff9245..21dfb3bdeb3e0 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -1412,34 +1412,6 @@ protected function prepare_item_for_database( $request ) { // Post password. if ( ! empty( $schema['properties']['password'] ) && isset( $request['password'] ) ) { $prepared_post->post_password = $request['password']; - - if ( '' !== $request['password'] ) { - if ( ! empty( $schema['properties']['sticky'] ) && ! empty( $request['sticky'] ) ) { - return new WP_Error( - 'rest_invalid_field', - __( 'A post can not be sticky and have a password.' ), - array( 'status' => 400 ) - ); - } - - if ( ! empty( $prepared_post->ID ) && is_sticky( $prepared_post->ID ) ) { - return new WP_Error( - 'rest_invalid_field', - __( 'A sticky post can not be password protected.' ), - array( 'status' => 400 ) - ); - } - } - } - - if ( ! empty( $schema['properties']['sticky'] ) && ! empty( $request['sticky'] ) ) { - if ( ! empty( $prepared_post->ID ) && post_password_required( $prepared_post->ID ) ) { - return new WP_Error( - 'rest_invalid_field', - __( 'A password protected post can not be set to sticky.' ), - array( 'status' => 400 ) - ); - } } // Parent. diff --git a/tests/phpunit/tests/admin/includesPost.php b/tests/phpunit/tests/admin/includesPost.php index fc4ba33776de5..d9823af05c4fd 100644 --- a/tests/phpunit/tests/admin/includesPost.php +++ b/tests/phpunit/tests/admin/includesPost.php @@ -1369,4 +1369,72 @@ public function test_user_get_refreshed_metabox_nonce() { $this->assertNotEmpty( $response['wp-refresh-metabox-loader-nonces']['replace']['_wpnonce'] ); $this->assertNotEmpty( $response['wp-refresh-metabox-loader-nonces']['replace']['metabox_loader_nonce'] ); } + + /** + * Ensures that edit_post() allows a post to be both sticky and password protected. + * + * @ticket 64810 + * + * @covers ::edit_post + */ + public function test_edit_post_retains_sticky_when_password_visibility_is_set() { + wp_set_current_user( self::$admin_id ); + + $post_id = self::factory()->post->create( + array( + 'post_status' => 'publish', + 'post_author' => self::$admin_id, + ) + ); + stick_post( $post_id ); + $this->assertTrue( is_sticky( $post_id ), 'The post was not sticky to begin with.' ); + + edit_post( + array( + 'post_ID' => $post_id, + 'post_title' => 'Protected and sticky', + 'post_status' => 'publish', + 'post_password' => 'secret', + 'visibility' => 'password', + 'sticky' => 'sticky', + ) + ); + + $this->assertSame( 'secret', get_post( $post_id )->post_password ); + $this->assertTrue( is_sticky( $post_id ), 'The post should remain sticky when password protected.' ); + } + + /** + * Ensures that an existing password protected post can be set to sticky via edit_post(). + * + * @ticket 64810 + * + * @covers ::edit_post + */ + public function test_edit_post_allows_sticking_password_protected_post() { + wp_set_current_user( self::$admin_id ); + + $post_id = self::factory()->post->create( + array( + 'post_status' => 'publish', + 'post_password' => 'secret', + 'post_author' => self::$admin_id, + ) + ); + $this->assertFalse( is_sticky( $post_id ), 'The post was sticky to begin with.' ); + + edit_post( + array( + 'post_ID' => $post_id, + 'post_title' => 'Protected and sticky', + 'post_status' => 'publish', + 'post_password' => 'secret', + 'visibility' => 'password', + 'sticky' => 'sticky', + ) + ); + + $this->assertSame( 'secret', get_post( $post_id )->post_password ); + $this->assertTrue( is_sticky( $post_id ), 'The password protected post should be made sticky.' ); + } } diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index 7f4f09d78b308..14b490bb929a4 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -3527,7 +3527,10 @@ public function test_create_post_with_empty_string_password_and_sticky() { $this->assertSame( '', $data['password'] ); } - public function test_create_post_with_password_and_sticky_fails() { + /** + * @ticket 64810 + */ + public function test_create_post_with_password_and_sticky_succeeds() { wp_set_current_user( self::$editor_id ); $request = new WP_REST_Request( 'POST', '/wp/v2/posts' ); @@ -3540,7 +3543,40 @@ public function test_create_post_with_password_and_sticky_fails() { $request->set_body_params( $params ); $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_field', $response, 400 ); + $this->assertSame( 201, $response->get_status() ); + $data = $response->get_data(); + $this->assertSame( '123', $data['password'] ); + $this->assertTrue( $data['sticky'] ); + $this->assertTrue( is_sticky( $data['id'] ) ); + $this->assertSame( '123', get_post( $data['id'] )->post_password ); + } + + /** + * @ticket 64810 + */ + public function test_update_post_with_password_and_sticky_succeeds() { + wp_set_current_user( self::$editor_id ); + + $post_id = self::factory()->post->create( + array( + 'post_status' => 'publish', + 'post_author' => self::$editor_id, + ) + ); + stick_post( $post_id ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . $post_id ); + $params = $this->set_post_data( + array( + 'password' => 'secret', + ) + ); + $request->set_body_params( $params ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( 200, $response->get_status() ); + $this->assertTrue( is_sticky( $post_id ) ); + $this->assertSame( 'secret', get_post( $post_id )->post_password ); } public function test_create_post_custom_date() { @@ -4320,23 +4356,10 @@ public function test_update_post_with_empty_password() { $this->assertSame( '', $data['password'] ); } - public function test_update_post_with_password_and_sticky_fails() { - wp_set_current_user( self::$editor_id ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) ); - $params = $this->set_post_data( - array( - 'password' => '123', - 'sticky' => true, - ) - ); - $request->set_body_params( $params ); - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_invalid_field', $response, 400 ); - } - - public function test_update_stick_post_with_password_fails() { + /** + * @ticket 64810 + */ + public function test_update_stick_post_with_password_succeeds() { wp_set_current_user( self::$editor_id ); stick_post( self::$post_id ); @@ -4350,10 +4373,15 @@ public function test_update_stick_post_with_password_fails() { $request->set_body_params( $params ); $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_field', $response, 400 ); + $this->assertSame( 200, $response->get_status() ); + $this->assertSame( '123', get_post( self::$post_id )->post_password ); + $this->assertTrue( is_sticky( self::$post_id ) ); } - public function test_update_password_protected_post_with_sticky_fails() { + /** + * @ticket 64810 + */ + public function test_update_password_protected_post_with_sticky_succeeds() { wp_set_current_user( self::$editor_id ); wp_update_post( @@ -4372,7 +4400,8 @@ public function test_update_password_protected_post_with_sticky_fails() { $request->set_body_params( $params ); $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_field', $response, 400 ); + $this->assertSame( 200, $response->get_status() ); + $this->assertTrue( is_sticky( self::$post_id ) ); } public function test_update_post_with_quotes_in_title() { diff --git a/tests/phpunit/tests/xmlrpc/wp/newPost.php b/tests/phpunit/tests/xmlrpc/wp/newPost.php index c6386a1f23d5b..314fe68d45340 100644 --- a/tests/phpunit/tests/xmlrpc/wp/newPost.php +++ b/tests/phpunit/tests/xmlrpc/wp/newPost.php @@ -446,4 +446,25 @@ public function test_valid_IXR_post_date_gmt() { $this->assertStringMatchesFormat( '%d', $result ); $this->assertSame( $date_string, $fetched_post->post_date_gmt ); } + + /** + * @ticket 64810 + */ + public function test_post_sticky_with_password() { + $this->make_user_by_role( 'editor' ); + + $post = array( + 'post_title' => 'Sticky with password', + 'post_content' => 'Test content', + 'post_status' => 'publish', + 'post_password' => 'secret', + 'sticky' => true, + ); + + $result = $this->myxmlrpcserver->wp_newPost( array( 1, 'editor', 'editor', $post ) ); + $this->assertNotIXRError( $result ); + $post_id = (int) $result; + $this->assertTrue( is_sticky( $post_id ) ); + $this->assertSame( 'secret', get_post( $post_id )->post_password ); + } }