diff --git a/src/wp-admin/includes/admin-filters.php b/src/wp-admin/includes/admin-filters.php index e80c111dde..33354cb073 100644 --- a/src/wp-admin/includes/admin-filters.php +++ b/src/wp-admin/includes/admin-filters.php @@ -80,6 +80,7 @@ add_filter( 'heartbeat_received', 'wp_refresh_post_lock', 10, 3 ); add_filter( 'heartbeat_received', 'heartbeat_autosave', 500, 2 ); add_filter( 'wp_refresh_nonces', 'wp_refresh_post_nonces', 10, 3 ); +add_filter( 'wp_refresh_nonces', 'wp_refresh_metabox_loader_nonces', 10, 2 ); add_filter( 'wp_refresh_nonces', 'wp_refresh_heartbeat_nonces' ); add_filter( 'heartbeat_settings', 'wp_heartbeat_set_suspension' ); diff --git a/src/wp-admin/includes/misc.php b/src/wp-admin/includes/misc.php index 94337fee7d..65cf69ab31 100644 --- a/src/wp-admin/includes/misc.php +++ b/src/wp-admin/includes/misc.php @@ -1255,6 +1255,41 @@ function wp_refresh_post_nonces( $response, $data, $screen_id ) { return $response; } +/** + * Refresh nonces used with meta boxes in the block editor. + * + * @since 6.1.0 + * + * @param array $response The Heartbeat response. + * @param array $data The $_POST data sent. + * @return array The Heartbeat response. + */ +function wp_refresh_metabox_loader_nonces( $response, $data ) { + if ( empty( $data['wp-refresh-metabox-loader-nonces'] ) ) { + return $response; + } + + $received = $data['wp-refresh-metabox-loader-nonces']; + $post_id = (int) $received['post_id']; + + if ( ! $post_id ) { + return $response; + } + + if ( ! current_user_can( 'edit_post', $post_id ) ) { + return $response; + } + + $response['wp-refresh-metabox-loader-nonces'] = array( + 'replace' => array( + 'metabox_loader_nonce' => wp_create_nonce( 'meta-box-loader' ), + '_wpnonce' => wp_create_nonce( 'update-post_' . $post_id ), + ), + ); + + return $response; +} + /** * Adds the latest Heartbeat and REST-API nonce to the Heartbeat response. * diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index 8eb0368220..1abe542316 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -2334,6 +2334,50 @@ function the_block_editor_meta_boxes() { wp_add_inline_script( 'wp-lists', $script ); } + /* + * Refresh nonces used by the meta box loader. + * + * The logic is very similar to that provided by post.js for the classic editor. + */ + $script = "( function( $ ) { + var check, timeout; + + function schedule() { + check = false; + window.clearTimeout( timeout ); + timeout = window.setTimeout( function() { check = true; }, 300000 ); + } + + $( document ).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) { + var post_id, \$authCheck = $( '#wp-auth-check-wrap' ); + + if ( check || ( \$authCheck.length && ! \$authCheck.hasClass( 'hidden' ) ) ) { + if ( ( post_id = $( '#post_ID' ).val() ) && $( '#_wpnonce' ).val() ) { + data['wp-refresh-metabox-loader-nonces'] = { + post_id: post_id + }; + } + } + }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) { + var nonces = data['wp-refresh-metabox-loader-nonces']; + + if ( nonces ) { + if ( nonces.replace ) { + if ( nonces.replace.metabox_loader_nonce && window._wpMetaBoxUrl && wp.url ) { + window._wpMetaBoxUrl= wp.url.addQueryArgs( window._wpMetaBoxUrl, { 'meta-box-loader-nonce': nonces.replace.metabox_loader_nonce } ); + } + + if ( nonces.replace._wpnonce ) { + $( '#_wpnonce' ).val( nonces.replace._wpnonce ); + } + } + } + }).ready( function() { + schedule(); + }); + } )( jQuery );"; + wp_add_inline_script( 'heartbeat', $script ); + // Reset meta box data. $wp_meta_boxes = $_original_meta_boxes; } diff --git a/tests/phpunit/tests/admin/includesPost.php b/tests/phpunit/tests/admin/includesPost.php index eaf20d987e..2a41131a92 100644 --- a/tests/phpunit/tests/admin/includesPost.php +++ b/tests/phpunit/tests/admin/includesPost.php @@ -1016,4 +1016,42 @@ class Tests_Admin_IncludesPost extends WP_UnitTestCase { $this->assertSame( 0, post_exists( $title, null, null, $post_type, 'draft' ) ); $this->assertSame( 0, post_exists( $title, null, null, 'wp_tests', $post_status ) ); } + + /** + * Test refreshed nonce for metabox loader. + * + * @return void + */ + public function test_user_get_refreshed_metabox_nonce() { + + // Create a post by the current user. + wp_set_current_user( self::$editor_id ); + + $post_data = array( + 'post_content' => 'Test post content', + 'post_title' => 'Test post title', + 'post_excerpt' => 'Test post excerpt', + 'post_author' => self::$editor_id, + 'post_status' => 'draft', + ); + $post_id = wp_insert_post( $post_data ); + + // Simulate the $_POST data from the heartbeat. + $data = array( + 'wp-refresh-metabox-loader-nonces' => array( + 'post_id' => (string) $post_id, + ), + 'wp-refresh-post-lock' => array( + 'lock' => '1658203298:1', + 'post_id' => (string) $post_id, + ), + ); + + // Call the function we're testing. + $response = wp_refresh_metabox_loader_nonces( array(), $data ); + + // Ensure that both nonces were created. + $this->assertNotEmpty( $response['wp-refresh-metabox-loader-nonces']['replace']['_wpnonce'] ); + $this->assertNotEmpty( $response['wp-refresh-metabox-loader-nonces']['replace']['metabox_loader_nonce'] ); + } }