diff --git a/src/wp-admin/post.php b/src/wp-admin/post.php index dd7bad1bb3830..055e0abefef63 100644 --- a/src/wp-admin/post.php +++ b/src/wp-admin/post.php @@ -72,13 +72,16 @@ switch ( $action ) { case 'post-quickdraft-save': // Check nonce and capabilities. - $nonce = $_REQUEST['_wpnonce']; + $nonce = $_REQUEST['_wpnonce'] ?? ''; + $post_id = (int) ( $_REQUEST['post_ID'] ?? 0 ); + // Explicitly check for a positive ID to avoid falling back to the global $post object. + $post = ( $post_id > 0 ) ? get_post( $post_id ) : null; $error_msg = false; // For output of the Quick Draft dashboard widget. require_once ABSPATH . 'wp-admin/includes/dashboard.php'; - if ( ! wp_verify_nonce( $nonce, 'add-post' ) ) { + if ( ! $post || ! wp_verify_nonce( $nonce, 'add-post' ) ) { $error_msg = __( 'Unable to submit this form, please refresh and try again.' ); } @@ -90,7 +93,6 @@ return wp_dashboard_quick_press( $error_msg ); } - $post = get_post( $_REQUEST['post_ID'] ); check_admin_referer( 'add-' . $post->post_type ); $_POST['comment_status'] = get_default_comment_status( $post->post_type ); diff --git a/tests/phpunit/tests/admin/wpPost.php b/tests/phpunit/tests/admin/wpPost.php new file mode 100644 index 0000000000000..ec69faba8b91a --- /dev/null +++ b/tests/phpunit/tests/admin/wpPost.php @@ -0,0 +1,111 @@ +user->create( array( 'role' => 'administrator' ) ); + } + + public function set_up() { + parent::set_up(); + wp_set_current_user( self::$admin_id ); + set_current_screen( 'dashboard' ); + } + + public function tear_down() { + parent::tear_down(); + set_current_screen( 'front' ); + unset( $_REQUEST['_wpnonce'], $_REQUEST['post_ID'], $_REQUEST['action'] ); + } + + /** + * Test Happy Path: Successfully validating a correct nonce and post_ID. + * + * @ticket 65052 + */ + public function test_post_quickdraft_save_happy_path() { + $post_id = self::factory()->post->create( array( 'post_status' => 'draft' ) ); + $nonce = wp_create_nonce( 'add-post' ); + + $_REQUEST['_wpnonce'] = $nonce; + $_REQUEST['post_ID'] = $post_id; + + $nonce_req = $_REQUEST['_wpnonce'] ?? ''; + $id_req = (int) ( $_REQUEST['post_ID'] ?? 0 ); + $post = $id_req ? get_post( $id_req ) : null; + + $error_msg = false; + if ( ! $post || ! wp_verify_nonce( $nonce_req, 'add-post' ) ) { + $error_msg = __( 'Unable to submit this form, please refresh and try again.' ); + } + + $this->assertFalse( $error_msg, 'Happy path should not produce an error message.' ); + $this->assertNotNull( $post ); + $this->assertEquals( $post_id, $post->ID ); + } + + /** + * test post quickdraft save missing nonce + * + * @ticket 65052 + */ + public function test_post_quickdraft_save_missing_nonce() { + $_REQUEST['action'] = 'post-quickdraft-save'; + unset( $_REQUEST['_wpnonce'] ); // invliad nonce + $_REQUEST['post_ID'] = 0; + + $nonce = $_REQUEST['_wpnonce'] ?? ''; + $post_id = (int) ( $_REQUEST['post_ID'] ?? 0 ); + $post = $post_id ? get_post( $post_id ) : null; + + $error_msg = false; + if ( ! $post || ! wp_verify_nonce( $nonce, 'add-post' ) ) { + $error_msg = __( 'Unable to submit this form, please refresh and try again.' ); + } + + $this->assertSame( 'Unable to submit this form, please refresh and try again.', $error_msg ); + } + + /** + * test post quickdraft save invalid all + * + * @ticket 65052 + */ + public function test_post_quickdraft_save_invalid_all() { + $_REQUEST['_wpnonce'] = 'invalid_nonce'; + $_REQUEST['post_ID'] = -1; // invalid ID + + $nonce = $_REQUEST['_wpnonce'] ?? ''; + $post_id = (int) ( $_REQUEST['post_ID'] ?? 0 ); + $post = $post_id ? get_post( $post_id ) : null; + + $this->assertNull( $post ); + + $error_msg = false; + if ( ! $post || ! wp_verify_nonce( $nonce, 'add-post' ) ) { + $error_msg = __( 'Unable to submit this form, please refresh and try again.' ); + } + + $this->assertNotEmpty( $error_msg ); + } + + /** + * test post quickdraft save should not use global post + * + * @ticket 65052 + */ + public function test_post_quickdraft_save_should_not_use_global_post() { + $other_post_id = self::factory()->post->create(); + $GLOBALS['post'] = get_post( $other_post_id ); + + $_REQUEST['post_ID'] = 0; + $post_id = (int) $_REQUEST['post_ID']; + $post = ( $post_id > 0 ) ? get_post( $post_id ) : null; + + $this->assertNull( $post, 'Should return null instead of falling back to global post.' ); + } +}