Skip to content

Commit 251716d

Browse files
committed
Admin: Correct logic flow for nonce and capability checks in post.php
1 parent 4d3b0b9 commit 251716d

2 files changed

Lines changed: 116 additions & 3 deletions

File tree

src/wp-admin/post.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,16 @@
7272
switch ( $action ) {
7373
case 'post-quickdraft-save':
7474
// Check nonce and capabilities.
75-
$nonce = $_REQUEST['_wpnonce'];
75+
$nonce = $_REQUEST['_wpnonce'] ?? '';
76+
$post_id = (int) ( $_REQUEST['post_ID'] ?? 0 );
77+
// Explicitly check for a positive ID to avoid falling back to the global $post object.
78+
$post = ( $post_id > 0 ) ? get_post( $post_id ) : null;
7679
$error_msg = false;
7780

7881
// For output of the Quick Draft dashboard widget.
7982
require_once ABSPATH . 'wp-admin/includes/dashboard.php';
8083

81-
if ( ! wp_verify_nonce( $nonce, 'add-post' ) ) {
84+
if ( ! $post || ! wp_verify_nonce( $nonce, 'add-post' ) ) {
8285
$error_msg = __( 'Unable to submit this form, please refresh and try again.' );
8386
}
8487

@@ -90,7 +93,6 @@
9093
return wp_dashboard_quick_press( $error_msg );
9194
}
9295

93-
$post = get_post( $_REQUEST['post_ID'] );
9496
check_admin_referer( 'add-' . $post->post_type );
9597

9698
$_POST['comment_status'] = get_default_comment_status( $post->post_type );
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
/**
4+
* @group admin
5+
*/
6+
class Tests_Admin_Post_QuickDraftSave extends WP_UnitTestCase {
7+
protected static $admin_id;
8+
9+
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ): void {
10+
self::$admin_id = $factory->user->create( array( 'role' => 'administrator' ) );
11+
}
12+
13+
public function set_up() {
14+
parent::set_up();
15+
wp_set_current_user( self::$admin_id );
16+
set_current_screen( 'dashboard' );
17+
}
18+
19+
public function tear_down() {
20+
parent::tear_down();
21+
set_current_screen( 'front' );
22+
unset( $_REQUEST['_wpnonce'], $_REQUEST['post_ID'], $_REQUEST['action'] );
23+
}
24+
25+
/**
26+
* Test Happy Path: Successfully validating a correct nonce and post_ID.
27+
*
28+
* @ticket 65052
29+
*/
30+
public function test_post_quickdraft_save_happy_path() {
31+
$post_id = self::factory()->post->create( array( 'post_status' => 'draft' ) );
32+
$nonce = wp_create_nonce( 'add-post' );
33+
34+
$_REQUEST['_wpnonce'] = $nonce;
35+
$_REQUEST['post_ID'] = $post_id;
36+
37+
$nonce_req = $_REQUEST['_wpnonce'] ?? '';
38+
$id_req = (int) ( $_REQUEST['post_ID'] ?? 0 );
39+
$post = $id_req ? get_post( $id_req ) : null;
40+
41+
$error_msg = false;
42+
if ( ! $post || ! wp_verify_nonce( $nonce_req, 'add-post' ) ) {
43+
$error_msg = __( 'Unable to submit this form, please refresh and try again.' );
44+
}
45+
46+
$this->assertFalse( $error_msg, 'Happy path should not produce an error message.' );
47+
$this->assertNotNull( $post );
48+
$this->assertEquals( $post_id, $post->ID );
49+
}
50+
51+
/**
52+
* test post quickdraft save missing nonce
53+
*
54+
* @ticket 65052
55+
*/
56+
public function test_post_quickdraft_save_missing_nonce() {
57+
$_REQUEST['action'] = 'post-quickdraft-save';
58+
unset( $_REQUEST['_wpnonce'] ); // invliad nonce
59+
$_REQUEST['post_ID'] = 0;
60+
61+
$nonce = $_REQUEST['_wpnonce'] ?? '';
62+
$post_id = (int) ( $_REQUEST['post_ID'] ?? 0 );
63+
$post = $post_id ? get_post( $post_id ) : null;
64+
65+
$error_msg = false;
66+
if ( ! $post || ! wp_verify_nonce( $nonce, 'add-post' ) ) {
67+
$error_msg = __( 'Unable to submit this form, please refresh and try again.' );
68+
}
69+
70+
$this->assertSame( 'Unable to submit this form, please refresh and try again.', $error_msg );
71+
}
72+
73+
/**
74+
* test post quickdraft save invalid all
75+
*
76+
* @ticket 65052
77+
*/
78+
public function test_post_quickdraft_save_invalid_all() {
79+
$_REQUEST['_wpnonce'] = 'invalid_nonce';
80+
$_REQUEST['post_ID'] = -1; // invalid ID
81+
82+
$nonce = $_REQUEST['_wpnonce'] ?? '';
83+
$post_id = (int) ( $_REQUEST['post_ID'] ?? 0 );
84+
$post = $post_id ? get_post( $post_id ) : null;
85+
86+
$this->assertNull( $post );
87+
88+
$error_msg = false;
89+
if ( ! $post || ! wp_verify_nonce( $nonce, 'add-post' ) ) {
90+
$error_msg = __( 'Unable to submit this form, please refresh and try again.' );
91+
}
92+
93+
$this->assertNotEmpty( $error_msg );
94+
}
95+
96+
/**
97+
* test post quickdraft save should not use global post
98+
*
99+
* @ticket 65052
100+
*/
101+
public function test_post_quickdraft_save_should_not_use_global_post() {
102+
$other_post_id = self::factory()->post->create();
103+
$GLOBALS['post'] = get_post( $other_post_id );
104+
105+
$_REQUEST['post_ID'] = 0;
106+
$post_id = (int) $_REQUEST['post_ID'];
107+
$post = ( $post_id > 0 ) ? get_post( $post_id ) : null;
108+
109+
$this->assertNull( $post, 'Should return null instead of falling back to global post.' );
110+
}
111+
}

0 commit comments

Comments
 (0)